summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/pages/session
diff options
context:
space:
mode:
authorShoubhit Dash <[email protected]>2026-04-03 20:24:57 +0530
committerGitHub <[email protected]>2026-04-03 09:54:57 -0500
commit35350b1d25a56665cf065eba68929fc00617fdd2 (patch)
tree91bf53b5d87ff9532ebf0a779c4dbe7bc99148f3 /packages/app/src/pages/session
parent263dcf75b548810a149f08ea5e32e0f6754128d5 (diff)
downloadopencode-35350b1d25a56665cf065eba68929fc00617fdd2.tar.gz
opencode-35350b1d25a56665cf065eba68929fc00617fdd2.zip
feat: restore git-backed review modes (#20845)
Diffstat (limited to 'packages/app/src/pages/session')
-rw-r--r--packages/app/src/pages/session/session-side-panel.tsx58
-rw-r--r--packages/app/src/pages/session/use-session-commands.tsx6
2 files changed, 23 insertions, 41 deletions
diff --git a/packages/app/src/pages/session/session-side-panel.tsx b/packages/app/src/pages/session/session-side-panel.tsx
index c07942627..86f932ea2 100644
--- a/packages/app/src/pages/session/session-side-panel.tsx
+++ b/packages/app/src/pages/session/session-side-panel.tsx
@@ -8,6 +8,7 @@ import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
import { Mark } from "@opencode-ai/ui/logo"
import { DragDropProvider, DragDropSensors, DragOverlay, SortableProvider, closestCenter } from "@thisbeyond/solid-dnd"
import type { DragEvent } from "@thisbeyond/solid-dnd"
+import type { FileDiff } from "@opencode-ai/sdk/v2"
import { ConstrainDragYAxis, getDraggableId } from "@/utils/solid-dnd"
import { useDialog } from "@opencode-ai/ui/context/dialog"
@@ -18,7 +19,6 @@ import { useCommand } from "@/context/command"
import { useFile, type SelectedLineRange } from "@/context/file"
import { useLanguage } from "@/context/language"
import { useLayout } from "@/context/layout"
-import { useSync } from "@/context/sync"
import { createFileTabListSync } from "@/pages/session/file-tab-scroll"
import { FileTabContent } from "@/pages/session/file-tabs"
import { createOpenSessionFileTab, createSessionTabs, getTabReorderIndex, type Sizing } from "@/pages/session/helpers"
@@ -26,6 +26,12 @@ import { setSessionHandoff } from "@/pages/session/handoff"
import { useSessionLayout } from "@/pages/session/session-layout"
export function SessionSidePanel(props: {
+ canReview: () => boolean
+ diffs: () => FileDiff[]
+ diffsReady: () => boolean
+ empty: () => string
+ hasReview: () => boolean
+ reviewCount: () => number
reviewPanel: () => JSX.Element
activeDiff?: string
focusReviewDiff: (path: string) => void
@@ -33,12 +39,11 @@ export function SessionSidePanel(props: {
size: Sizing
}) {
const layout = useLayout()
- const sync = useSync()
const file = useFile()
const language = useLanguage()
const command = useCommand()
const dialog = useDialog()
- const { params, sessionKey, tabs, view } = useSessionLayout()
+ const { sessionKey, tabs, view } = useSessionLayout()
const isDesktop = createMediaQuery("(min-width: 768px)")
@@ -53,24 +58,7 @@ export function SessionSidePanel(props: {
})
const treeWidth = createMemo(() => (fileOpen() ? `${layout.fileTree.width()}px` : "0px"))
- const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
- const diffs = createMemo(() => (params.id ? (sync.data.session_diff[params.id] ?? []) : []))
- const reviewCount = createMemo(() => Math.max(info()?.summary?.files ?? 0, diffs().length))
- const hasReview = createMemo(() => reviewCount() > 0)
- const diffsReady = createMemo(() => {
- const id = params.id
- if (!id) return true
- if (!hasReview()) return true
- return sync.data.session_diff[id] !== undefined
- })
-
- const reviewEmptyKey = createMemo(() => {
- if (sync.project && !sync.project.vcs) return "session.review.noVcs"
- if (sync.data.config.snapshot === false) return "session.review.noSnapshot"
- return "session.review.noChanges"
- })
-
- const diffFiles = createMemo(() => diffs().map((d) => d.file))
+ const diffFiles = createMemo(() => props.diffs().map((d) => d.file))
const kinds = createMemo(() => {
const merge = (a: "add" | "del" | "mix" | undefined, b: "add" | "del" | "mix") => {
if (!a) return b
@@ -81,7 +69,7 @@ export function SessionSidePanel(props: {
const normalize = (p: string) => p.replaceAll("\\\\", "/").replace(/\/+$/, "")
const out = new Map<string, "add" | "del" | "mix">()
- for (const diff of diffs()) {
+ for (const diff of props.diffs()) {
const file = normalize(diff.file)
const kind = diff.status === "added" ? "add" : diff.status === "deleted" ? "del" : "mix"
@@ -135,7 +123,7 @@ export function SessionSidePanel(props: {
pathFromTab: file.pathFromTab,
normalizeTab,
review: reviewTab,
- hasReview,
+ hasReview: props.canReview,
})
const contextOpen = tabState.contextOpen
const openedTabs = tabState.openedTabs
@@ -240,12 +228,12 @@ export function SessionSidePanel(props: {
onCleanup(stop)
}}
>
- <Show when={reviewTab()}>
+ <Show when={reviewTab() && props.canReview()}>
<Tabs.Trigger value="review">
<div class="flex items-center gap-1.5">
<div>{language.t("session.tab.review")}</div>
- <Show when={hasReview()}>
- <div>{reviewCount()}</div>
+ <Show when={props.hasReview()}>
+ <div>{props.reviewCount()}</div>
</Show>
</div>
</Tabs.Trigger>
@@ -304,7 +292,7 @@ export function SessionSidePanel(props: {
</Tabs.List>
</div>
- <Show when={reviewTab()}>
+ <Show when={reviewTab() && props.canReview()}>
<Tabs.Content value="review" class="flex flex-col h-full overflow-hidden contain-strict">
<Show when={activeTab() === "review"}>{props.reviewPanel()}</Show>
</Tabs.Content>
@@ -378,8 +366,10 @@ export function SessionSidePanel(props: {
>
<Tabs.List>
<Tabs.Trigger value="changes" class="flex-1" classes={{ button: "w-full" }}>
- {reviewCount()}{" "}
- {language.t(reviewCount() === 1 ? "session.review.change.one" : "session.review.change.other")}
+ {props.reviewCount()}{" "}
+ {language.t(
+ props.reviewCount() === 1 ? "session.review.change.one" : "session.review.change.other",
+ )}
</Tabs.Trigger>
<Tabs.Trigger value="all" class="flex-1" classes={{ button: "w-full" }}>
{language.t("session.files.all")}
@@ -387,9 +377,9 @@ export function SessionSidePanel(props: {
</Tabs.List>
<Tabs.Content value="changes" class="bg-background-stronger px-3 py-0">
<Switch>
- <Match when={hasReview()}>
+ <Match when={props.hasReview() || !props.diffsReady()}>
<Show
- when={diffsReady()}
+ when={props.diffsReady()}
fallback={
<div class="px-2 py-2 text-12-regular text-text-weak">
{language.t("common.loading")}
@@ -408,11 +398,7 @@ export function SessionSidePanel(props: {
/>
</Show>
</Match>
- <Match when={true}>
- {empty(
- language.t(sync.project && !sync.project.vcs ? "session.review.noChanges" : reviewEmptyKey()),
- )}
- </Match>
+ <Match when={true}>{empty(props.empty())}</Match>
</Switch>
</Tabs.Content>
<Tabs.Content value="all" class="bg-background-stronger px-3 py-0">
diff --git a/packages/app/src/pages/session/use-session-commands.tsx b/packages/app/src/pages/session/use-session-commands.tsx
index 430fd46f8..239795373 100644
--- a/packages/app/src/pages/session/use-session-commands.tsx
+++ b/packages/app/src/pages/session/use-session-commands.tsx
@@ -52,11 +52,7 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
if (!id) return
return sync.session.get(id)
}
- const hasReview = () => {
- const id = params.id
- if (!id) return false
- return Math.max(info()?.summary?.files ?? 0, (sync.data.session_diff[id] ?? []).length) > 0
- }
+ const hasReview = () => !!params.id
const normalizeTab = (tab: string) => {
if (!tab.startsWith("file://")) return tab
return file.tab(tab)