feat: persist viewed files across page reloads - #35
Open
adamward459 wants to merge 1 commit into
Open
Conversation
Marking a file as viewed collapsed it, but the state lived only in React state, so a browser refresh expanded every file again. It was also lost on any live diff refetch, since the collapse set is rebuilt from scratch whenever the diff object changes. Viewed paths are now stored in localStorage keyed by repo root and ref, capped to the ten most recently used refs so the store can't grow without bound. Each mark is stored alongside a fingerprint of the file's diff. On load the fingerprint is recomputed and the mark is kept only if it still matches, so a file you edited since reviewing it expands again while untouched files stay collapsed. The fingerprint covers file identity, status, and every add/delete line, excluding context lines, hunk headers and line numbers so an unrelated edit elsewhere in the file doesn't unmark a reviewed hunk. Content is trimmed so toggling the hide-whitespace filter doesn't churn marks. Viewed now also takes precedence over a file having comments, which previously force-expanded it.
Author
|
Test video: 2026-08-15.at.22.40.25.mp4 |
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.
Problem
Marking a file as viewed collapses it, but the state lives only in React state (
useStateindiff-page.tsx). A browser refresh expands every file again.It's also lost on any live diff refetch — the collapse set is rebuilt from scratch whenever the
diffobject identity changes, andreviewedFileswas never an input to that rebuild.This bites hardest in the common loop: review → edit code → refresh → everything you already went through is open again.
Approach
Viewed paths are stored in
localStorage, keyed by repo root and ref, capped to the ten most recently used refs so the store can't grow without bound. Keyed by repo root rather than origin because ports get recycled between repos.Each mark is stored alongside a fingerprint of that file's diff. On load the fingerprint is recomputed and the mark kept only if it still matches — so a file you edited since reviewing it expands again, while untouched files stay collapsed. Same behaviour as GitHub's "viewed" checkbox.
The fingerprint covers file identity, status, and every add/delete line. It deliberately excludes context lines, hunk headers and line numbers, so an unrelated edit elsewhere in the file doesn't unmark a hunk you already reviewed, and trims content so toggling the hide-whitespace filter doesn't churn marks.
One behaviour change worth flagging: viewed now takes precedence over a file having comments, which previously force-expanded it. Ticking the box reads as an explicit "I'm done here".
Changes
packages/ui/src/lib/viewed-storage.ts(new) — fingerprinting, reconciliation, and the LRU-capped store, as pure functionspackages/ui/tests/viewed-storage.test.ts(new) — 25 testspackages/ui/src/components/diff/diff-page.tsx— restore on load, persist on change, comment-precedence fix (+32 / -2)Testing
npm test— 100/100 passing. New tests cover fingerprint stability (identical file, indentation-only change, context/line-number shift) and sensitivity (edited line, rename, status change), reconciliation, LRU eviction, and storage round-trip including corrupt JSON and version mismatch.Eviction orders by a monotonic write counter rather than
Date.now(), since several writes can land in the same millisecond and tie.Manual check: mark two files viewed, edit one, refresh — the edited one expands, the other stays collapsed.