Lazy full file hydration - #15420
Conversation
There was a problem hiding this comment.
Pull request overview
Adds “lazy full file hydration” for the Lite workspace diff viewer by wiring CodeView’s loadDiffFiles callback to fetch full file contents on demand via TanStack Query, rather than eagerly hydrating full files up front.
Changes:
- Plumbs
loadDiffFilesinto the CodeView options to enable on-demand loading of full file contents for diffs. - Introduces blob/workspace file query usage (via
blobFileQueryOptions/workspaceFileQueryOptions) and usesuseQueryClient().fetchQuery()for imperative fetching.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
1d4116e to
8221060
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Suppressed comments (1)
apps/lite/ui/src/routes/project/$id/workspace/Details.tsx:1352
loadDiffFilestreats onlyUncommittedChangesas workspace-backed. In this codebaseFileParentcan also beBranch, and branch diffs are applied to the workspace (seeapps/lite/ui/src/operands.ts+ existingImageDifflogic). As written, branch diffs will incorrectly hydrate the “new” file fromgetBlobFileinstead of the workspace state.
// Don't await yet, retain prospective parallelisation.
const asyncNewFile =
fileParent._tag === "UncommittedChanges"
? loadWorkspaceFile(change.path)
: loadBlobFile(change.path, change.status.subject.state.id);
8221060 to
fffe5af
Compare
On large files there is sometimes a flicker where syntax highlighting appears to disappear before reappearing. To the best of my understanding this is Pierre-side, where once production of syntax highlighting has eclipsed 300ms the diff stops waiting and hydrates the full file as plaintext.
fffe5af to
0207414
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Suppressed comments (3)
apps/lite/ui/src/routes/project/$id/workspace/Details.tsx:1336
fileByPath.get(fileDiff.name)can returnundefined(e.g., CodeView holds a stale snapshot or the name doesn’t match the map key). In that case the currentfile?.patch?.type !== "Patch"branch throws a misleading "Cannot expand non-patch diff" error. Add an explicit not-found check so failures are diagnosable.
const file = fileByPath.get(fileDiff.name);
if (file?.patch?.type !== "Patch") throw new Error("Cannot expand non-patch diff");
apps/lite/ui/src/routes/project/$id/workspace/Details.tsx:1375
- After allowing additions/deletions, the
asyncNewFilecomputation still assumeschange.status.subject.state.idexists, which will crash for deletions. Also, for pure renames it’s more consistent to return both old/new contents (they’re identical) so split views don’t look like an addition. HandleAddition/Deletionexplicitly before buildingasyncNewFile, and load the old file forrename-purerenames.
// Don't await yet, retain prospective parallelisation.
const asyncNewFile =
fileParent._tag === "UncommittedChanges"
? loadWorkspaceFile(change.path)
: loadBlobFile(change.path, change.status.subject.state.id);
apps/lite/ui/src/routes/project/$id/workspace/Details.tsx:1345
loadDiffFilescurrently only allowsModificationandRename, but CodeView can request full-file hydration for additions/deletions as well (andsynthesizeFilePatchalready produces patch headers for those statuses). If this guard stays as-is, expanding full-file views for added/deleted files will always throw.
This issue also appears on line 1371 of the same file.
if (change.status.type !== "Modification" && change.status.type !== "Rename")
throw new Error(`Cannot load full files for ${fileDiff.name}`);
Closes GB-1836.