Lite: file tree: give directory rows (most of) the features from file rows - #15949
cbjeukendrup wants to merge 9 commits into
Conversation
3bf280f to
4e7695a
Compare
|
@cbjeukendrup thanks for the PR! |
|
A folder is marked 'reviewed' iff all files under it are reviewed: Schermopname.2026-09-21.om.09.37.00.mov |
Gotcha. I wonder if we should add the ability to check files and folders via right-click? Currently, it only works via the UI button, and reviewing a folder isn't possible yet. |
|
I could look into that. 'Marking a folder (un)reviewed' means 'marking all files under it (un)reviewed', right? (Or do you think we should give folders their own reviewed state? I'm not sure that'd be a good idea, because the folder is in a way only a transient UI thing: if the file tree changes (files added/removed), the folder might be split, or disappear its parent.) |
A directory row held `filePaths`, which is enough for the checkbox and drag sources but says nothing about what each file is. Carrying the items themselves lets a directory tell a change from a conflict and reach the `TreeChange` behind it, which is what acting on a subtree needs. `filePaths` was a projection of the items, so keeping both would have been two sources of truth. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cut, absorb, uncommit and discard were each written out three times — in the file row's menu, in the checked-set toolbar, and (for uncommit) as a closure in Details threaded down as a prop. They differ only in what they are addressed to, so they now live in `useFileSetActions`, which names its subject by address and looks the changes back up itself. `useFileSetSubject` is the other half: it decides whether a row stands for its own files or gives way to the checked set, and reports the count so a label can say what it is about to act on. Cut, absorb and uncommit now count as discard always has. A linked worktree's files keep the terms they were given: they cut into the workspace like any other, but absorb and discard act on the project's own checkout, so `useFileSetActions` reports neither and `fileSetMenuItems` offers neither. Said once there, it holds for every row addressed to a set, not just the file row it was written for. `useDiscardFileChanges` loses its `extendToCheckedFiles` flag: deciding the subject was never the mutation's job. The `uncommit`/`canUncommit` props threaded through FilesTree and the diff viewer go with it, the worktree lane's included. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Right-click a folder, or reach for its kebab, and it offers what its path alone can answer for: open it in an editor, reveal it in the file manager, copy its path, and fold or unfold it. None of these ask what the folder belongs to, so they come straight from the group a file row already uses. The row splits the way a file row does, so a list being scrolled pays for none of it — but the scrolling half still renders the row whole: an inert button where the kebab goes, and nothing behind a right-click that has no menu to open yet. A row that gained its controls back as the list settled would be its own flicker. That placeholder is the one a file row already uses, so it moves to `Row.tsx`, next to the toolbar it sits in. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cut, absorb, uncommit and discard now reach a folder, addressed to every file below it, and the labels count what they are about to touch. A folder gives way to the checked set on the same terms a file does — a file when it is checked, a folder when its box reads checked, which is when every file below it is. Conflicts below a folder are no part of that subject; they have nothing to commit or discard yet. They get "Mark as Resolved" instead, which already took a list of paths. Knowing what it belongs to also tells a folder where it lives: in a linked worktree it opens and reveals against that checkout, as a file row there already did, and offers the same acts a file row there is offered. Drops "Copy File Paths": a folder already copies its own path like any other row, and the bulk variant duplicated that without adding anything a user could not already do file by file. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Absorb, discard and uncommit keyed off a single change, which a directory row has none of, so they quietly did nothing there. They now take what the row stands for — its own file, or every file below a folder — the same subject its menu is addressed to. Reveal was gated on file rows outright; a folder has a path in the worktree like anything else. Open in editor was limited to uncommitted files, though the menu has always offered it wherever a row is listed; now the chord agrees with the menu. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The label carries the whole path, which a folded chain of segments and a deep indent both need, and the checkbox teaches its chord — both as a file row has always done. Mid-scroll the checkbox drops both, as a file row's does: no tooltip and no handler, so the row teaches no chord it cannot yet act on. The label's tooltip stays — a path is a path whether or not the list has settled. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Playwright cannot open a native menu, but it can see the button that opens one, and the rest of what a directory row answers for — its fold state, and the files its checkbox stands for — is ordinary DOM. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A directory stands for the files below it, so it reads their reviewed state the way its checkbox reads their checked state: reviewed once every change below it is, conflicts not counting. The row then recedes and shows the same tick a reviewed file row shows in place of its change type. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
yes, a folder just represents its files. Technically I'm not sure how feasible it is, but I thought it would be consistent and nice for UX. @samhh wonder wdyt |
Reviewing was the one thing a row said but could not do: the tick was shown in both lists, and the only way to set it was the diff header's own button, one file at a time. Both row menus now offer it, and a directory offers it for every change below it at once — the same subtree its checkbox and its other acts stand for. Reviewing records the version of the diff it saw, and only the patch carries one, so the act names its changes rather than their addresses and looks their diffs up before marking: the ones the diff pane loads anyway, usually already in the cache. Unlike the acts beside it, it does not give way to the checked set — how far a reader has got through a row is the row's own business, as marking its conflicts resolved is — and it is the one item branch files get, since review state is kept for them too. The diff header leaves it out: it offers reviewing in its own chrome, and its button also folds the file away, which a menu item would not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4e7695a to
6e4efa5
Compare
|
How would this be? Schermopname.2026-09-21.om.10.16.09.mov |
Context menu

'Reviewed' check marks
