diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx
index 79c8d42f55..a5c7bf90b3 100644
--- a/packages/app/src/pages/session.tsx
+++ b/packages/app/src/pages/session.tsx
@@ -862,6 +862,36 @@ export default function Page() {
)
+ const reviewEmpty = (input: { loadingClass: string; emptyClass: string }) => {
+ if (store.changes === "turn") return emptyTurn()
+
+ if (hasReview() && !diffsReady()) {
+ return
{language.t("session.review.loadingChanges")}
+ }
+
+ if (reviewEmptyKey() === "session.review.noVcs") {
+ return (
+
+ )
+ }
+
+ return (
+
+ )
+ }
+
const reviewContent = (input: {
diffStyle: DiffStyle
onDiffStyleChange?: (style: DiffStyle) => void
@@ -870,98 +900,25 @@ export default function Page() {
emptyClass: string
}) => (
-
-
- setTree("reviewScroll", el)}
- focusedFile={tree.activeDiff}
- onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })}
- onLineCommentUpdate={updateCommentInContext}
- onLineCommentDelete={removeCommentFromContext}
- lineCommentActions={reviewCommentActions()}
- comments={comments.all()}
- focusedComment={comments.focus()}
- onFocusedCommentChange={comments.setFocus}
- onViewFile={openReviewFile}
- classes={input.classes}
- />
-
-
- {language.t("session.review.loadingChanges")}}
- >
- setTree("reviewScroll", el)}
- focusedFile={tree.activeDiff}
- onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })}
- onLineCommentUpdate={updateCommentInContext}
- onLineCommentDelete={removeCommentFromContext}
- lineCommentActions={reviewCommentActions()}
- comments={comments.all()}
- focusedComment={comments.focus()}
- onFocusedCommentChange={comments.setFocus}
- onViewFile={openReviewFile}
- classes={input.classes}
- />
-
-
-
-
-
-
Create a Git repository
-
- Track, review, and undo changes in this project
-
-
-
-
- ) : (
-
- )
- }
- diffs={reviewDiffs}
- view={view}
- diffStyle={input.diffStyle}
- onDiffStyleChange={input.onDiffStyleChange}
- onScrollRef={(el) => setTree("reviewScroll", el)}
- focusedFile={tree.activeDiff}
- onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })}
- onLineCommentUpdate={updateCommentInContext}
- onLineCommentDelete={removeCommentFromContext}
- lineCommentActions={reviewCommentActions()}
- comments={comments.all()}
- focusedComment={comments.focus()}
- onFocusedCommentChange={comments.setFocus}
- onViewFile={openReviewFile}
- classes={input.classes}
- />
-
-
+ setTree("reviewScroll", el)}
+ focusedFile={tree.activeDiff}
+ onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })}
+ onLineCommentUpdate={updateCommentInContext}
+ onLineCommentDelete={removeCommentFromContext}
+ lineCommentActions={reviewCommentActions()}
+ comments={comments.all()}
+ focusedComment={comments.focus()}
+ onFocusedCommentChange={comments.setFocus}
+ onViewFile={openReviewFile}
+ classes={input.classes}
+ />
)
diff --git a/packages/ui/src/components/file.tsx b/packages/ui/src/components/file.tsx
index fa430e286d..15915dd52d 100644
--- a/packages/ui/src/components/file.tsx
+++ b/packages/ui/src/components/file.tsx
@@ -491,6 +491,29 @@ function renderViewer(opts: {
opts.onReady()
}
+function preserve(viewer: Viewer) {
+ const root = scrollParent(viewer.wrapper)
+ if (!root) return () => {}
+
+ const high = viewer.container.getBoundingClientRect().height
+ if (!high) return () => {}
+
+ const top = viewer.wrapper.getBoundingClientRect().top - root.getBoundingClientRect().top
+ const prev = viewer.container.style.minHeight
+ viewer.container.style.minHeight = `${Math.ceil(high)}px`
+
+ let done = false
+ return () => {
+ if (done) return
+ done = true
+ viewer.container.style.minHeight = prev
+
+ const next = viewer.wrapper.getBoundingClientRect().top - root.getBoundingClientRect().top
+ const delta = next - top
+ if (delta) root.scrollTop += delta
+ }
+}
+
function scrollParent(el: HTMLElement): HTMLElement | undefined {
let parent = el.parentElement
while (parent) {
@@ -990,12 +1013,13 @@ function DiffViewer(props: DiffFileProps) {
return { ...perf, disableLineNumbers: true }
})
- const notify = () => {
+ const notify = (done?: VoidFunction) => {
notifyRendered({
viewer,
isReady: (root) => root.querySelector("[data-line]") != null,
settleFrames: 1,
onReady: () => {
+ done?.()
setSelectedLines(viewer.lastSelection)
viewer.find.refresh({ reset: true })
local.onRendered?.()
@@ -1016,6 +1040,9 @@ function DiffViewer(props: DiffFileProps) {
const virtualizer = virtuals.get()
const beforeContents = typeof local.before?.contents === "string" ? local.before.contents : ""
const afterContents = typeof local.after?.contents === "string" ? local.after.contents : ""
+ const done = preserve(viewer)
+
+ onCleanup(done)
const cacheKey = (contents: string) => {
if (!large()) return sampledChecksum(contents, contents.length)
@@ -1040,7 +1067,7 @@ function DiffViewer(props: DiffFileProps) {
containerWrapper: viewer.container,
})
},
- onReady: notify,
+ onReady: () => notify(done),
})
})
diff --git a/packages/ui/src/components/session-review.tsx b/packages/ui/src/components/session-review.tsx
index 61920d9f3f..49c561e0bd 100644
--- a/packages/ui/src/components/session-review.tsx
+++ b/packages/ui/src/components/session-review.tsx
@@ -60,6 +60,8 @@ export type SessionReviewCommentActions = {
export type SessionReviewFocus = { file: string; id: string }
+type ReviewDiff = FileDiff & { preloaded?: PreloadMultiFileDiffResult }
+
export interface SessionReviewProps {
title?: JSX.Element
empty?: JSX.Element
@@ -83,7 +85,7 @@ export interface SessionReviewProps {
classList?: Record
classes?: { root?: string; header?: string; container?: string }
actions?: JSX.Element
- diffs: (FileDiff & { preloaded?: PreloadMultiFileDiffResult })[]
+ diffs: ReviewDiff[]
onViewFile?: (file: string) => void
readFile?: (path: string) => Promise
}
@@ -146,8 +148,8 @@ export const SessionReview = (props: SessionReviewProps) => {
const [opened, setOpened] = createSignal(null)
const open = () => props.open ?? store.open
- const files = createMemo(() => props.diffs.map((d) => d.file))
- const diffs = createMemo(() => new Map(props.diffs.map((d) => [d.file, d] as const)))
+ const files = createMemo(() => props.diffs.map((diff) => diff.file))
+ const diffs = createMemo(() => new Map(props.diffs.map((diff) => [diff.file, diff] as const)))
const diffStyle = () => props.diffStyle ?? (props.split ? "split" : "unified")
const hasDiffs = () => files().length > 0
@@ -282,8 +284,7 @@ export const SessionReview = (props: SessionReviewProps) => {
{(file) => {
let wrapper: HTMLDivElement | undefined
- const diff = createMemo(() => diffs().get(file))
- const item = () => diff()!
+ const item = createMemo(() => diffs().get(file)!)
const expanded = createMemo(() => open().includes(file))
const force = () => !!store.force[file]