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 ( +
+
+
Create a Git repository
+
+ Track, review, and undo changes in this project +
+
+ +
+ ) + } + + return ( +
+
{language.t(reviewEmptyKey())}
+
+ ) + } + 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 -
-
- - - ) : ( -
-
{language.t(reviewEmptyKey())}
-
- ) - } - 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]