Add selective line restoration, file-history annotation, and sidebar section menu #52

Merged
Christoph merged 0 commits from refs/pull/52/head into main 2026-09-18 18:48:06 +00:00
Christoph commented 2026-09-18 18:47:52 +00:00 (Migrated from git.cbsk-tech.de)

This change implements three user-facing and internal updates: selective restoration of lines from a historical commit into the working file, an annotation on file history entries that marks when the latest history entry matches the working tree, and a small left-sidebar section menu to toggle visibility of non-branch panels. It also includes a couple of UI polish and styling tweaks (repository select cursor and per-group accents in the branch panel).

What changed (behavioral summary)

  • Selective line restoration from historical commits

    • New Tauri command get_file_restore_patch(path, commit, file) that produces the reverse diff (historical -> working) for a single file. The patch text is filtered to remove mode lines and returned as UTF-8 text.
    • apply_file_patch now supports an additional action string "restore-lines". Applying this action validates the patch (validate_restore_patch) and then checks/applies it via the existing patch application helpers.
    • Validation enforces: the target is an existing regular file, the patch contains only text-line changes (rejects mode, rename, binary, and git-binary-patch style lines), and the patch must only modify the single selected file (checked via git apply --numstat -z).
    • Frontend wiring: App.svelte imports and uses getFileRestorePatch, opens a line-restore flow from the compare dialog (onRestoreLines), exposes a Restore lines… button in CompareDialog.svelte when applicable, and provides restoreSelectedLines which invokes applyFilePatch(..., "restore-lines"), refreshes diffs/history/views, and surfaces any errors.
    • Tests added (Rust unit tests) cover that selected-line restores preserve unselected changes and the index, and that invalid or stale patches are rejected.
  • File history annotation

    • The file-history command result is now wrapped in FileHistoryCommit { commit: GitCommit, matches_working_tree: bool }.
    • list_file_history now returns the annotated commits; annotate_file_history computes matches_working_tree by running a git diff --quiet of the first returned commit against the working tree for regular files only. The implementation only marks the first entry (index 0) as matching the working tree when appropriate.
    • A unit test was added that asserts the boolean toggles only when the current working file exactly matches the latest commit entry and under changes like local edits, staging, committing, and deletion.
  • Sidebar section menu and visibility toggles

    • A new SidebarSectionMenu component is imported and opened on contextmenu over the left sidebar (right-click). It allows toggling visibility for non-branch panels: Worktrees, Tags, Stashes, Files (Explorer).
    • Visibility is persisted in localStorage under gitlite.sidebarVisibility.v1. The layout and handle visibility logic (panel ordering and sizing) were updated to respect the sidebarVisibility map.
    • A small accessibility/behavior helper restores focus when the menu is closed.
  • UI and styling tweaks

    • RepoTabs.svelte: change repository-select cursor from grab to pointer for clickable select elements.
    • BranchPanel.svelte: per-group accent styling for branch group headers (local vs remote) via CSS variables and color-mix, with a subtle left inset shadow and hover color changes.

Implementation notes (helpful to review)

  • Rust backend

    • New functions in src-tauri/src/git.rs: get_file_restore_patch, validate_restore_patch, and annotate_file_history. apply_file_patch was extended to handle the restore-lines action by validating and then applying the patch.
    • list_file_history signature in the Rust tauri back-end now returns Vec<FileHistoryCommit> (annotated commits) instead of Vec<GitCommit>.
    • main.rs exports get_file_restore_patch to the Tauri command list so the frontend can call it.
  • Frontend

    • App.svelte additions: state and functions to open the historical-line restore flow (openHistoricalLineRestore), to fetch the historical patch (getFileRestorePatch), to apply selected lines (restoreSelectedLines), and to manage sidebarVisibility (load/save, toggle). The LinePatch component is passed a new restoreCommit prop in its invocation.
    • CompareDialog.svelte gained an optional onRestoreLines callback prop and shows a Restore lines… button when the comparison represents a historical comparison (no to_hash) and the selected file is a modified file (no old_path). When clicked it triggers the openHistoricalLineRestore flow.
    • Sidebar visibility is respected in the computed layout (buildLeftSidebarRows, sidebarHandleVisible, expandedSidebarPanels). Right-click on the left sidebar opens the section menu.

Tests

  • New tests added in src-tauri/src/git.rs tests module:
    • restore_lines_preserves_unselected_changes_and_index
    • restore_lines_rejects_stale_or_wrong_file_patches
    • file_history_marks_only_an_identical_current_file

No test execution results were provided. The commits and tests are present in the diff but the PR does not include CI output.

Recommended checks for reviewers:

  • Backend unit tests: run cargo test for the src-tauri crate to verify the new tests and ensure no regressions.
  • Manual UI flow: open a repository, open a historical comparison (a compare shown with from_hash and no to_hash), select a modified file in the comparison, click the new Restore lines… button, select/apply a subset of hunks in the line-patch dialog and confirm that:
    1. only the selected lines are restored from the historical commit,
    2. other unstaged or staged changes are preserved as expected,
    3. index/staged blob contents remain unchanged when the test expects it.
  • Verify file-history API shape: consumers of the list_file_history tauri command should now expect objects with commit and matches_working_tree keys; ensure frontend FileHistoryDialog uses the new shape (the diff shows corresponding UI changes, but please confirm no external consumers rely on the old plain GitCommit array).
  • Sidebar persistence: toggle several panels via the new section menu and reload the app to confirm visibility persists in localStorage under the key gitlite.sidebarVisibility.v1.

Compatibility / reviewer actions

  • The tauri return shape for list_file_history changed to include matches_working_tree. If any external code or plugin expected a plain GitCommit list from that command, it must be updated to handle FileHistoryCommit objects.
  • The new get_file_restore_patch command is exported; review callers for correct usage and error handling.
  • The new restore-lines action path in apply_file_patch performs stricter validation than generic patch application — this is intentional and enforced in validate_restore_patch.

If you want, I can list the specific files that changed for each of the bullet items above or produce a short checklist of smoke tests to run in the UI (open compare, right-click sidebar, etc.).

This change implements three user-facing and internal updates: selective restoration of lines from a historical commit into the working file, an annotation on file history entries that marks when the latest history entry matches the working tree, and a small left-sidebar section menu to toggle visibility of non-branch panels. It also includes a couple of UI polish and styling tweaks (repository select cursor and per-group accents in the branch panel). ## What changed (behavioral summary) - Selective line restoration from historical commits - New Tauri command `get_file_restore_patch(path, commit, file)` that produces the reverse diff (historical -> working) for a single file. The patch text is filtered to remove mode lines and returned as UTF-8 text. - `apply_file_patch` now supports an additional action string `"restore-lines"`. Applying this action validates the patch (`validate_restore_patch`) and then checks/applies it via the existing patch application helpers. - Validation enforces: the target is an existing regular file, the patch contains only text-line changes (rejects mode, rename, binary, and git-binary-patch style lines), and the patch must only modify the single selected file (checked via `git apply --numstat -z`). - Frontend wiring: `App.svelte` imports and uses `getFileRestorePatch`, opens a line-restore flow from the compare dialog (`onRestoreLines`), exposes a `Restore lines…` button in `CompareDialog.svelte` when applicable, and provides `restoreSelectedLines` which invokes `applyFilePatch(..., "restore-lines")`, refreshes diffs/history/views, and surfaces any errors. - Tests added (Rust unit tests) cover that selected-line restores preserve unselected changes and the index, and that invalid or stale patches are rejected. - File history annotation - The file-history command result is now wrapped in `FileHistoryCommit { commit: GitCommit, matches_working_tree: bool }`. - `list_file_history` now returns the annotated commits; `annotate_file_history` computes `matches_working_tree` by running a `git diff --quiet` of the first returned commit against the working tree for regular files only. The implementation only marks the first entry (index 0) as matching the working tree when appropriate. - A unit test was added that asserts the boolean toggles only when the current working file exactly matches the latest commit entry and under changes like local edits, staging, committing, and deletion. - Sidebar section menu and visibility toggles - A new `SidebarSectionMenu` component is imported and opened on contextmenu over the left sidebar (right-click). It allows toggling visibility for non-branch panels: Worktrees, Tags, Stashes, Files (Explorer). - Visibility is persisted in localStorage under `gitlite.sidebarVisibility.v1`. The layout and handle visibility logic (panel ordering and sizing) were updated to respect the `sidebarVisibility` map. - A small accessibility/behavior helper restores focus when the menu is closed. - UI and styling tweaks - `RepoTabs.svelte`: change repository-select cursor from `grab` to `pointer` for clickable select elements. - `BranchPanel.svelte`: per-group accent styling for branch group headers (local vs remote) via CSS variables and color-mix, with a subtle left inset shadow and hover color changes. ## Implementation notes (helpful to review) - Rust backend - New functions in `src-tauri/src/git.rs`: `get_file_restore_patch`, `validate_restore_patch`, and `annotate_file_history`. `apply_file_patch` was extended to handle the `restore-lines` action by validating and then applying the patch. - `list_file_history` signature in the Rust tauri back-end now returns `Vec<FileHistoryCommit>` (annotated commits) instead of `Vec<GitCommit>`. - `main.rs` exports `get_file_restore_patch` to the Tauri command list so the frontend can call it. - Frontend - `App.svelte` additions: state and functions to open the historical-line restore flow (`openHistoricalLineRestore`), to fetch the historical patch (`getFileRestorePatch`), to apply selected lines (`restoreSelectedLines`), and to manage `sidebarVisibility` (load/save, toggle). The `LinePatch` component is passed a new `restoreCommit` prop in its invocation. - `CompareDialog.svelte` gained an optional `onRestoreLines` callback prop and shows a `Restore lines…` button when the comparison represents a historical comparison (no `to_hash`) and the selected file is a modified file (no `old_path`). When clicked it triggers the `openHistoricalLineRestore` flow. - Sidebar visibility is respected in the computed layout (`buildLeftSidebarRows`, `sidebarHandleVisible`, `expandedSidebarPanels`). Right-click on the left sidebar opens the section menu. ## Tests - New tests added in `src-tauri/src/git.rs` tests module: - `restore_lines_preserves_unselected_changes_and_index` - `restore_lines_rejects_stale_or_wrong_file_patches` - `file_history_marks_only_an_identical_current_file` No test execution results were provided. The commits and tests are present in the diff but the PR does not include CI output. Recommended checks for reviewers: - Backend unit tests: run `cargo test` for the `src-tauri` crate to verify the new tests and ensure no regressions. - Manual UI flow: open a repository, open a historical comparison (a compare shown with `from_hash` and no `to_hash`), select a modified file in the comparison, click the new `Restore lines…` button, select/apply a subset of hunks in the line-patch dialog and confirm that: 1) only the selected lines are restored from the historical commit, 2) other unstaged or staged changes are preserved as expected, 3) index/staged blob contents remain unchanged when the test expects it. - Verify file-history API shape: consumers of the `list_file_history` tauri command should now expect objects with `commit` and `matches_working_tree` keys; ensure frontend `FileHistoryDialog` uses the new shape (the diff shows corresponding UI changes, but please confirm no external consumers rely on the old plain `GitCommit` array). - Sidebar persistence: toggle several panels via the new section menu and reload the app to confirm visibility persists in localStorage under the key `gitlite.sidebarVisibility.v1`. ## Compatibility / reviewer actions - The tauri return shape for `list_file_history` changed to include `matches_working_tree`. If any external code or plugin expected a plain `GitCommit` list from that command, it must be updated to handle `FileHistoryCommit` objects. - The new `get_file_restore_patch` command is exported; review callers for correct usage and error handling. - The new `restore-lines` action path in `apply_file_patch` performs stricter validation than generic patch application — this is intentional and enforced in `validate_restore_patch`. If you want, I can list the specific files that changed for each of the bullet items above or produce a short checklist of smoke tests to run in the UI (open compare, right-click sidebar, etc.).
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Christoph/Gitty!52
No description provided.