feat(app): persist review state per session (#35488)
This commit is contained in:
parent
83d633fd13
commit
aa52d30d7f
3 changed files with 222 additions and 23 deletions
152
packages/app/e2e/regression/review-state-persistence.spec.ts
Normal file
152
packages/app/e2e/regression/review-state-persistence.spec.ts
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||||
|
import { expect, test, type Page } from "@playwright/test"
|
||||||
|
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||||
|
import { expectSessionTitle } from "../utils/waits"
|
||||||
|
|
||||||
|
const directory = "C:/OpenCode/ReviewStatePersistence"
|
||||||
|
const projectID = "proj_review_state_persistence"
|
||||||
|
const sessionA = "ses_review_state_a"
|
||||||
|
const sessionB = "ses_review_state_b"
|
||||||
|
const titleA = "Alpha review state"
|
||||||
|
const titleB = "Beta review state"
|
||||||
|
const server = `http://${process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1"}:${process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"}`
|
||||||
|
|
||||||
|
test.use({ viewport: { width: 1440, height: 900 } })
|
||||||
|
|
||||||
|
test("restores review mode and selected file per session", async ({ page }) => {
|
||||||
|
await setup(page)
|
||||||
|
await page.goto(sessionHref(sessionA))
|
||||||
|
await expectSessionTitle(page, titleA)
|
||||||
|
await page.getByRole("button", { name: "Toggle review" }).click()
|
||||||
|
|
||||||
|
await selectMode(page, "Git changes", "Branch changes")
|
||||||
|
await selectFile(page, "beta.ts")
|
||||||
|
|
||||||
|
await switchSession(page, titleB)
|
||||||
|
await expect(page.getByRole("button", { name: "Git changes" })).toBeVisible()
|
||||||
|
await selectFile(page, "gamma.ts")
|
||||||
|
|
||||||
|
await switchSession(page, titleA)
|
||||||
|
await expect(page.getByRole("button", { name: "Branch changes" })).toBeVisible()
|
||||||
|
await expectSelectedFile(page, "beta.ts")
|
||||||
|
await selectMode(page, "Branch changes", "Git changes")
|
||||||
|
await expectSelectedFile(page, "alpha.ts")
|
||||||
|
await selectMode(page, "Git changes", "Branch changes")
|
||||||
|
await expectSelectedFile(page, "beta.ts")
|
||||||
|
|
||||||
|
await page.reload()
|
||||||
|
await expectSessionTitle(page, titleA)
|
||||||
|
await expect(page.getByRole("button", { name: "Branch changes" })).toBeVisible()
|
||||||
|
await expectSelectedFile(page, "beta.ts")
|
||||||
|
|
||||||
|
await switchSession(page, titleB)
|
||||||
|
await expect(page.getByRole("button", { name: "Git changes" })).toBeVisible()
|
||||||
|
await expectSelectedFile(page, "gamma.ts")
|
||||||
|
})
|
||||||
|
|
||||||
|
async function selectMode(page: Page, current: string, next: string) {
|
||||||
|
await page.getByRole("button", { name: current }).click()
|
||||||
|
await page.getByRole("option", { name: next }).click()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function selectFile(page: Page, file: string) {
|
||||||
|
await page.getByRole("button", { name: file }).click()
|
||||||
|
await expectSelectedFile(page, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function expectSelectedFile(page: Page, file: string) {
|
||||||
|
await expect(page.locator('[data-slot="session-review-v2-file-name"]')).toHaveText(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function switchSession(page: Page, title: string) {
|
||||||
|
await page.locator("[data-titlebar-tab-slot]", { hasText: title }).click()
|
||||||
|
await expectSessionTitle(page, title)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setup(page: Page) {
|
||||||
|
await mockOpenCodeServer(page, {
|
||||||
|
directory,
|
||||||
|
project: {
|
||||||
|
id: projectID,
|
||||||
|
worktree: directory,
|
||||||
|
vcs: "git",
|
||||||
|
name: "review-state-persistence",
|
||||||
|
time: { created: 1700000000000, updated: 1700000000000 },
|
||||||
|
sandboxes: [],
|
||||||
|
},
|
||||||
|
provider: {
|
||||||
|
all: [
|
||||||
|
{
|
||||||
|
id: "opencode",
|
||||||
|
name: "OpenCode",
|
||||||
|
models: { test: { id: "test", name: "Test", limit: { context: 200_000 } } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
connected: ["opencode"],
|
||||||
|
default: { providerID: "opencode", modelID: "test" },
|
||||||
|
},
|
||||||
|
sessions: [session(sessionA, titleA, 1700000000000), session(sessionB, titleB, 1700000001000)],
|
||||||
|
pageMessages: () => ({ items: [] }),
|
||||||
|
})
|
||||||
|
await page.route(/\/vcs(?:\?.*)?$/, (route) =>
|
||||||
|
route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: "application/json",
|
||||||
|
body: JSON.stringify({ branch: "feature", default_branch: "dev" }),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
await page.route("**/vcs/diff**", (route) =>
|
||||||
|
route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: "application/json",
|
||||||
|
body: JSON.stringify(
|
||||||
|
new URL(route.request().url()).searchParams.get("mode") === "branch"
|
||||||
|
? [diff("src/alpha.ts"), diff("src/beta.ts")]
|
||||||
|
: [diff("src/alpha.ts"), diff("src/gamma.ts")],
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
await page.addInitScript(
|
||||||
|
({ directory, server, sessions }) => {
|
||||||
|
localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } }))
|
||||||
|
localStorage.setItem(
|
||||||
|
"opencode.global.dat:server",
|
||||||
|
JSON.stringify({
|
||||||
|
projects: { local: [{ worktree: directory, expanded: true }] },
|
||||||
|
lastProject: { local: directory },
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
localStorage.setItem(
|
||||||
|
"opencode.window.browser.dat:tabs",
|
||||||
|
JSON.stringify(sessions.map((sessionId: string) => ({ type: "session", server, sessionId }))),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{ directory, server, sessions: [sessionA, sessionB] },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function session(id: string, title: string, created: number) {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
slug: id,
|
||||||
|
projectID,
|
||||||
|
directory,
|
||||||
|
title,
|
||||||
|
version: "dev",
|
||||||
|
time: { created, updated: created },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function diff(file: string) {
|
||||||
|
return {
|
||||||
|
file,
|
||||||
|
additions: 1,
|
||||||
|
deletions: 1,
|
||||||
|
status: "modified",
|
||||||
|
patch: `diff --git a/${file} b/${file}\n--- a/${file}\n+++ b/${file}\n@@ -1 +1 @@\n-export const value = 'before'\n+export const value = 'after'\n`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sessionHref(sessionID: string) {
|
||||||
|
return `/server/${base64Encode(server)}/session/${sessionID}`
|
||||||
|
}
|
||||||
|
|
@ -59,6 +59,8 @@ export function getProjectAvatarVariant(key?: string): ProjectAvatarVariant {
|
||||||
type SessionView = {
|
type SessionView = {
|
||||||
scroll: Record<string, SessionScroll>
|
scroll: Record<string, SessionScroll>
|
||||||
reviewOpen?: string[]
|
reviewOpen?: string[]
|
||||||
|
reviewMode?: ReviewChangeMode
|
||||||
|
reviewFile?: string
|
||||||
pendingMessage?: string
|
pendingMessage?: string
|
||||||
pendingMessageAt?: number
|
pendingMessageAt?: number
|
||||||
todoCollapsed?: boolean
|
todoCollapsed?: boolean
|
||||||
|
|
@ -75,6 +77,7 @@ export type LocalProject = Partial<Project> & { worktree: string; expanded: bool
|
||||||
export type HomeProjectSelection = { server: ServerConnection.Key; directory?: string }
|
export type HomeProjectSelection = { server: ServerConnection.Key; directory?: string }
|
||||||
|
|
||||||
export type ReviewDiffStyle = "unified" | "split"
|
export type ReviewDiffStyle = "unified" | "split"
|
||||||
|
export type ReviewChangeMode = "git" | "branch" | "turn"
|
||||||
export type ReviewPanelSource = "context-button" | "other"
|
export type ReviewPanelSource = "context-button" | "other"
|
||||||
|
|
||||||
export type LayoutRoute =
|
export type LayoutRoute =
|
||||||
|
|
@ -786,6 +789,14 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||||
view(sessionKey: string | Accessor<string>) {
|
view(sessionKey: string | Accessor<string>) {
|
||||||
const key = createSessionKeyReader(sessionKey, ensureKey)
|
const key = createSessionKeyReader(sessionKey, ensureKey)
|
||||||
const s = createMemo(() => store.sessionView[key()] ?? { scroll: {} })
|
const s = createMemo(() => store.sessionView[key()] ?? { scroll: {} })
|
||||||
|
const reviewMode = createMemo(() => {
|
||||||
|
const mode = s().reviewMode
|
||||||
|
if (mode === "git" || mode === "branch" || mode === "turn") return mode
|
||||||
|
})
|
||||||
|
const reviewFile = createMemo(() => {
|
||||||
|
const file = s().reviewFile
|
||||||
|
if (typeof file === "string") return file
|
||||||
|
})
|
||||||
const terminalOpened = createMemo(() => store.terminal?.opened ?? false)
|
const terminalOpened = createMemo(() => store.terminal?.opened ?? false)
|
||||||
const reviewPanelOpened = createMemo(() => store.review?.panelOpened ?? DEFAULT_REVIEW_PANEL_OPENED)
|
const reviewPanelOpened = createMemo(() => store.review?.panelOpened ?? DEFAULT_REVIEW_PANEL_OPENED)
|
||||||
const reviewPanelSource = createMemo(() => (reviewPanelOpened() ? ephemeral.reviewPanelSource : "other"))
|
const reviewPanelSource = createMemo(() => (reviewPanelOpened() ? ephemeral.reviewPanelSource : "other"))
|
||||||
|
|
@ -869,6 +880,32 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
review: {
|
review: {
|
||||||
|
mode: reviewMode,
|
||||||
|
setMode(mode: ReviewChangeMode) {
|
||||||
|
const session = key()
|
||||||
|
const current = store.sessionView[session]
|
||||||
|
if (!current) {
|
||||||
|
setStore("sessionView", session, { scroll: {}, reviewMode: mode })
|
||||||
|
prune(session)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (current.reviewMode === mode) return
|
||||||
|
setStore("sessionView", session, "reviewMode", mode)
|
||||||
|
prune(session)
|
||||||
|
},
|
||||||
|
file: reviewFile,
|
||||||
|
setFile(file: string) {
|
||||||
|
const session = key()
|
||||||
|
const current = store.sessionView[session]
|
||||||
|
if (!current) {
|
||||||
|
setStore("sessionView", session, { scroll: {}, reviewFile: file })
|
||||||
|
prune(session)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (current.reviewFile === file) return
|
||||||
|
setStore("sessionView", session, "reviewFile", file)
|
||||||
|
prune(session)
|
||||||
|
},
|
||||||
open: createMemo(() => s().reviewOpen ?? []),
|
open: createMemo(() => s().reviewOpen ?? []),
|
||||||
setOpen(open: string[]) {
|
setOpen(open: string[]) {
|
||||||
const session = key()
|
const session = key()
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,6 @@ type VcsMode = "git" | "branch"
|
||||||
const sessionViewState = () => ({
|
const sessionViewState = () => ({
|
||||||
messageId: undefined as string | undefined,
|
messageId: undefined as string | undefined,
|
||||||
mobileTab: "session" as "session" | "changes",
|
mobileTab: "session" as "session" | "changes",
|
||||||
changes: "git" as ChangeMode,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function isCurrentSessionNotFoundError(error: unknown, sessionID: string | undefined) {
|
function isCurrentSessionNotFoundError(error: unknown, sessionID: string | undefined) {
|
||||||
|
|
@ -348,6 +347,8 @@ export default function Page() {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { params, sessionKey, workspaceKey, tabs, view } = useSessionLayout()
|
const { params, sessionKey, workspaceKey, tabs, view } = useSessionLayout()
|
||||||
|
const reviewMode = () => view().review.mode() ?? "git"
|
||||||
|
const reviewFile = () => view().review.file()
|
||||||
const sessionOwnership = createSessionOwnership(sessionKey)
|
const sessionOwnership = createSessionOwnership(sessionKey)
|
||||||
const newSessionDesign = createMemo(() => settings.general.newLayoutDesigns())
|
const newSessionDesign = createMemo(() => settings.general.newLayoutDesigns())
|
||||||
|
|
||||||
|
|
@ -607,7 +608,8 @@ export default function Page() {
|
||||||
: store.mobileTab === "changes",
|
: store.mobileTab === "changes",
|
||||||
)
|
)
|
||||||
const vcsMode = createMemo<VcsMode | undefined>(() => {
|
const vcsMode = createMemo<VcsMode | undefined>(() => {
|
||||||
if (store.changes === "git" || store.changes === "branch") return store.changes
|
const mode = reviewMode()
|
||||||
|
if (mode === "git" || mode === "branch") return mode
|
||||||
})
|
})
|
||||||
const vcsKey = createMemo(
|
const vcsKey = createMemo(
|
||||||
() =>
|
() =>
|
||||||
|
|
@ -634,15 +636,21 @@ export default function Page() {
|
||||||
})
|
})
|
||||||
const refreshVcs = debounce(() => void queryClient.invalidateQueries({ queryKey: vcsKey() }), 100)
|
const refreshVcs = debounce(() => void queryClient.invalidateQueries({ queryKey: vcsKey() }), 100)
|
||||||
const reviewDiffs = () => {
|
const reviewDiffs = () => {
|
||||||
if (store.changes === "git" || store.changes === "branch")
|
if (reviewMode() === "git" || reviewMode() === "branch")
|
||||||
// avoids suspense
|
// avoids suspense
|
||||||
return vcsQuery.isFetched ? (vcsQuery.data ?? []) : []
|
return vcsQuery.isFetched ? (vcsQuery.data ?? []) : []
|
||||||
return turnDiffs()
|
return turnDiffs()
|
||||||
}
|
}
|
||||||
|
const activeReviewFile = () => {
|
||||||
|
const diffs = reviewDiffs()
|
||||||
|
const selected = reviewFile()
|
||||||
|
if (selected && diffs.some((diff) => diff.file === selected)) return selected
|
||||||
|
return diffs[0]?.file
|
||||||
|
}
|
||||||
const reviewCount = () => reviewDiffs().length
|
const reviewCount = () => reviewDiffs().length
|
||||||
const hasReview = () => reviewCount() > 0
|
const hasReview = () => reviewCount() > 0
|
||||||
const reviewReady = () => {
|
const reviewReady = () => {
|
||||||
if (store.changes === "git" || store.changes === "branch") return !vcsQuery.isPending
|
if (reviewMode() === "git" || reviewMode() === "branch") return !vcsQuery.isPending
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
const loadReviewDiff = async (file: string, version?: number): Promise<VcsFileDiff | undefined> => {
|
const loadReviewDiff = async (file: string, version?: number): Promise<VcsFileDiff | undefined> => {
|
||||||
|
|
@ -1002,12 +1010,15 @@ export default function Page() {
|
||||||
}
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
if (!layout.ready()) return
|
||||||
|
if (sync().status !== "complete") return
|
||||||
if (!sync().project) return
|
if (!sync().project) return
|
||||||
const list = changesOptions()
|
const list = changesOptions()
|
||||||
if (list.includes(store.changes)) return
|
const mode = reviewMode()
|
||||||
|
if (list.includes(mode)) return
|
||||||
const next = list[0]
|
const next = list[0]
|
||||||
if (!next) return
|
if (!next) return
|
||||||
setStore("changes", next)
|
view().review.setMode(next)
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(
|
createEffect(
|
||||||
|
|
@ -1027,7 +1038,6 @@ export default function Page() {
|
||||||
const [tree, setTree] = createStore({
|
const [tree, setTree] = createStore({
|
||||||
reviewScroll: undefined as HTMLDivElement | undefined,
|
reviewScroll: undefined as HTMLDivElement | undefined,
|
||||||
pendingDiff: undefined as string | undefined,
|
pendingDiff: undefined as string | undefined,
|
||||||
activeDiff: undefined as string | undefined,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(
|
createEffect(
|
||||||
|
|
@ -1037,7 +1047,6 @@ export default function Page() {
|
||||||
setTree({
|
setTree({
|
||||||
reviewScroll: undefined,
|
reviewScroll: undefined,
|
||||||
pendingDiff: undefined,
|
pendingDiff: undefined,
|
||||||
activeDiff: undefined,
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{ defer: true },
|
{ defer: true },
|
||||||
|
|
@ -1085,9 +1094,9 @@ export default function Page() {
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
options={changesOptions()}
|
options={changesOptions()}
|
||||||
current={store.changes}
|
current={reviewMode()}
|
||||||
label={changesLabel}
|
label={changesLabel}
|
||||||
onSelect={(option) => option && setStore("changes", option)}
|
onSelect={(option) => option && view().review.setMode(option)}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="small"
|
size="small"
|
||||||
valueClass="text-14-medium"
|
valueClass="text-14-medium"
|
||||||
|
|
@ -1104,11 +1113,11 @@ export default function Page() {
|
||||||
<SelectV2
|
<SelectV2
|
||||||
appearance="inline"
|
appearance="inline"
|
||||||
options={changesOptions()}
|
options={changesOptions()}
|
||||||
current={store.changes}
|
current={reviewMode()}
|
||||||
label={changesLabel}
|
label={changesLabel}
|
||||||
placement="bottom-start"
|
placement="bottom-start"
|
||||||
gutter={6}
|
gutter={6}
|
||||||
onSelect={(option) => option && setStore("changes", option)}
|
onSelect={(option) => option && view().review.setMode(option)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1136,18 +1145,18 @@ export default function Page() {
|
||||||
)
|
)
|
||||||
|
|
||||||
const reviewEmptyText = createMemo(() => {
|
const reviewEmptyText = createMemo(() => {
|
||||||
if (store.changes === "git") return language.t("session.review.noUncommittedChanges")
|
if (reviewMode() === "git") return language.t("session.review.noUncommittedChanges")
|
||||||
if (store.changes === "branch") return language.t("session.review.noBranchChanges")
|
if (reviewMode() === "branch") return language.t("session.review.noBranchChanges")
|
||||||
return language.t("session.review.noChanges")
|
return language.t("session.review.noChanges")
|
||||||
})
|
})
|
||||||
|
|
||||||
const reviewEmpty = (input: { loadingClass: string; emptyClass: string }) => {
|
const reviewEmpty = (input: { loadingClass: string; emptyClass: string }) => {
|
||||||
if (store.changes === "git" || store.changes === "branch") {
|
if (reviewMode() === "git" || reviewMode() === "branch") {
|
||||||
if (!reviewReady()) return <div class={input.loadingClass}>{language.t("session.review.loadingChanges")}</div>
|
if (!reviewReady()) return <div class={input.loadingClass}>{language.t("session.review.loadingChanges")}</div>
|
||||||
return empty(reviewEmptyText())
|
return empty(reviewEmptyText())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (store.changes === "turn") {
|
if (reviewMode() === "turn") {
|
||||||
if (nogit()) return createGit(input)
|
if (nogit()) return createGit(input)
|
||||||
return empty(reviewEmptyText())
|
return empty(reviewEmptyText())
|
||||||
}
|
}
|
||||||
|
|
@ -1160,10 +1169,10 @@ export default function Page() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const reviewEmptyV2 = () => {
|
const reviewEmptyV2 = () => {
|
||||||
if ((store.changes === "git" || store.changes === "branch") && !reviewReady()) {
|
if ((reviewMode() === "git" || reviewMode() === "branch") && !reviewReady()) {
|
||||||
return <div class="px-6 py-4 text-text-weak">{language.t("session.review.loadingChanges")}</div>
|
return <div class="px-6 py-4 text-text-weak">{language.t("session.review.loadingChanges")}</div>
|
||||||
}
|
}
|
||||||
if (store.changes === "turn" && nogit()) {
|
if (reviewMode() === "turn" && nogit()) {
|
||||||
return <SessionReviewEmptyNoGitV2 pending={gitMutation.isPending} onInitGit={initGit} />
|
return <SessionReviewEmptyNoGitV2 pending={gitMutation.isPending} onInitGit={initGit} />
|
||||||
}
|
}
|
||||||
return <SessionReviewEmptyChangesV2 />
|
return <SessionReviewEmptyChangesV2 />
|
||||||
|
|
@ -1185,7 +1194,7 @@ export default function Page() {
|
||||||
diffStyle={input.diffStyle}
|
diffStyle={input.diffStyle}
|
||||||
onDiffStyleChange={input.onDiffStyleChange}
|
onDiffStyleChange={input.onDiffStyleChange}
|
||||||
onScrollRef={(el) => setTree("reviewScroll", el)}
|
onScrollRef={(el) => setTree("reviewScroll", el)}
|
||||||
focusedFile={tree.activeDiff}
|
focusedFile={activeReviewFile()}
|
||||||
onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })}
|
onLineComment={(comment) => addCommentToContext({ ...comment, origin: "review" })}
|
||||||
onLineCommentUpdate={updateCommentInContext}
|
onLineCommentUpdate={updateCommentInContext}
|
||||||
onLineCommentDelete={removeCommentFromContext}
|
onLineCommentDelete={removeCommentFromContext}
|
||||||
|
|
@ -1221,7 +1230,7 @@ export default function Page() {
|
||||||
},
|
},
|
||||||
loadDiff: loadReviewDiff,
|
loadDiff: loadReviewDiff,
|
||||||
get activeFile() {
|
get activeFile() {
|
||||||
return tree.activeDiff
|
return activeReviewFile()
|
||||||
},
|
},
|
||||||
onSelectFile: focusReviewDiff,
|
onSelectFile: focusReviewDiff,
|
||||||
get diffStyle() {
|
get diffStyle() {
|
||||||
|
|
@ -1334,7 +1343,8 @@ export default function Page() {
|
||||||
const focusReviewDiff = (path: string) => {
|
const focusReviewDiff = (path: string) => {
|
||||||
openReviewPanel()
|
openReviewPanel()
|
||||||
view().review.openPath(path)
|
view().review.openPath(path)
|
||||||
setTree({ activeDiff: path, pendingDiff: path })
|
view().review.setFile(path)
|
||||||
|
setTree("pendingDiff", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
|
@ -2198,7 +2208,7 @@ export default function Page() {
|
||||||
reviewHasFocusableContent={hasReview}
|
reviewHasFocusableContent={hasReview}
|
||||||
reviewCount={reviewCount}
|
reviewCount={reviewCount}
|
||||||
reviewPanel={reviewPanel}
|
reviewPanel={reviewPanel}
|
||||||
activeDiff={tree.activeDiff}
|
activeDiff={activeReviewFile()}
|
||||||
focusReviewDiff={focusReviewDiff}
|
focusReviewDiff={focusReviewDiff}
|
||||||
reviewSnap={ui.reviewSnap}
|
reviewSnap={ui.reviewSnap}
|
||||||
size={size}
|
size={size}
|
||||||
|
|
@ -2224,7 +2234,7 @@ export default function Page() {
|
||||||
reviewCount={reviewCount}
|
reviewCount={reviewCount}
|
||||||
reviewPanel={reviewPanelV2}
|
reviewPanel={reviewPanelV2}
|
||||||
fileBrowserState={reviewV2State}
|
fileBrowserState={reviewV2State}
|
||||||
activeDiff={tree.activeDiff}
|
activeDiff={activeReviewFile()}
|
||||||
focusReviewDiff={focusReviewDiff}
|
focusReviewDiff={focusReviewDiff}
|
||||||
reviewSnap={ui.reviewSnap}
|
reviewSnap={ui.reviewSnap}
|
||||||
size={size}
|
size={size}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue