Skip to content

Add list/tree view toggle to the Git tab's Changes list - #98

Open
vivi7 wants to merge 1 commit into
doctly:mainfrom
vivi7:feat/git-changes-tree-view
Open

vivi7 wants to merge 1 commit into
doctly:mainfrom
vivi7:feat/git-changes-tree-view

Conversation

@vivi7

@vivi7 vivi7 commented Sep 26, 2026 •

Copy link
Copy Markdown

Summary

Adds a List / Tree switch to the Changes section of a project's Git tab. List is today's flat view and stays the default. Tree groups the changed files into collapsible folders, like View as Tree in VS Code / Cursor Source Control.

Screenshot 2026-09-26 at 22 39 32

Why

With many changes under a few deep directories (e.g. 30+ untracked files under backend/docs/… and backend/script/…), the flat list repeats the same long prefix on every row and it's hard to see where the changes are. A tree makes the shape of the change obvious and lets you fold away folders you've already looked at.

What it does

  • A small segmented control (list / tree icons) in the Changes heading, next to the "N files" count. It uses the same look as the existing .pane-seg control.
  • The choice is saved in localStorage (gitChangesView) as one global preference, like the diff mode in the file panel. Unknown values, or storage that throws, fall back to list.
  • The tree is built inside each status group (Conflicted, Modified, Added, …), the way VS Code keeps its SCM groups and builds a tree inside each one.
  • Folders come before files, sorted naturally and case-insensitively. Chains of folders with a single child collapse into one row (backend/docs/ai-engine), like VS Code's compact folders.
  • Folder rows show a chevron, a folder icon and a file count. Clicking one expands or collapses it (aria-expanded), and keyboard focus stays on that folder after the list re-renders. Collapse state lives in memory, per repository.
  • File rows in tree mode are a compact single line: status code + file name. The full path (and old → new for renames) plus the staged/unstaged/untracked label move into the tooltip.
  • Switching view or folding a folder repaints only the file list. The selected file and its diff pane are left alone: no flash, and no second diff fetch while one is still loading.

Implementation notes

  • public/project-git-view.js:
    • pure helpers buildGitChangeTree() and gitTreeRows(), easy to unit-test;
    • createGitFileRow(), shared by both modes, and createGitFolderRow();
    • paintGitChanges() takes { repaintDiff }, so a view switch or folder toggle skips the diff pane;
    • the toggle wiring lives in paintGitRepository().
  • public/projects-view.js: new PICONS.tree icon (Lucide list-tree).
  • public/style.css: .git-view-toggle / .git-view-btn, .git-folder-row, and .git-file-row.tree. Indentation uses a --depth custom property.
  • No changes to main-process code or IPC: the tree is built entirely from the changes array the renderer already receives.

Testing

  • New test/project-git-view.test.js (11 tests), which loads the real public/project-git-view.js in a vm context. It covers:
    • nesting and folders-first natural sort;
    • folder compaction, and cases that must not compact;
    • root-level files and renames;
    • collapsed folders hiding their descendants, depth values and file counts;
    • stored-mode fallbacks, including a throwing localStorage;
    • list vs tree render dispatch;
    • a folder click leaving the diff pane untouched and restoring focus.
  • npm test: 429/429 pass.
  • Manual check in Chromium against the real style.css and project-git-view.js, with a 33-file fixture:
    • both modes, collapse/expand, persistence across reload;
    • keyboard (Tab / Enter / Space);
    • the narrow single-column layout;
    • a file named <b>x-inject-test.sh renders as literal text;
    • no console errors.

A List/Tree switch in the Changes heading. List keeps today's flat view
and stays the default; Tree groups each status group's files into
collapsible folders, with single-child folder chains compacted into one
row (like VS Code's Source Control "View as Tree").

The choice is remembered in localStorage. Switching views or folding a
folder repaints only the file list, leaving the selection and diff pane
untouched, and keeps keyboard focus on the toggled folder.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant