Skip to content

Commit f135c0b

Browse files
authored
app: use tanstack query to load session vcs state (#22277)
1 parent ebe6ea5 commit f135c0b

1 file changed

Lines changed: 45 additions & 133 deletions

File tree

packages/app/src/pages/session.tsx

Lines changed: 45 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import type { Project, UserMessage, VcsFileDiff } from "@opencode-ai/sdk/v2"
1+
import type { Project, UserMessage } from "@opencode-ai/sdk/v2"
22
import { useDialog } from "@opencode-ai/ui/context/dialog"
3-
import { useMutation } from "@tanstack/solid-query"
3+
import { createQuery, skipToken, useMutation, useQueryClient } from "@tanstack/solid-query"
44
import {
55
batch,
66
onCleanup,
@@ -324,6 +324,7 @@ export default function Page() {
324324
const local = useLocal()
325325
const file = useFile()
326326
const sync = useSync()
327+
const queryClient = useQueryClient()
327328
const dialog = useDialog()
328329
const language = useLanguage()
329330
const sdk = useSDK()
@@ -518,26 +519,6 @@ export default function Page() {
518519
deferRender: false,
519520
})
520521

521-
const [vcs, setVcs] = createStore<{
522-
diff: {
523-
git: VcsFileDiff[]
524-
branch: VcsFileDiff[]
525-
}
526-
ready: {
527-
git: boolean
528-
branch: boolean
529-
}
530-
}>({
531-
diff: {
532-
git: [] as VcsFileDiff[],
533-
branch: [] as VcsFileDiff[],
534-
},
535-
ready: {
536-
git: false,
537-
branch: false,
538-
},
539-
})
540-
541522
const [followup, setFollowup] = persisted(
542523
Persist.workspace(sdk.directory, "followup", ["followup.v1"]),
543524
createStore<{
@@ -571,68 +552,6 @@ export default function Page() {
571552
let todoTimer: number | undefined
572553
let diffFrame: number | undefined
573554
let diffTimer: number | undefined
574-
const vcsTask = new Map<VcsMode, Promise<void>>()
575-
const vcsRun = new Map<VcsMode, number>()
576-
577-
const bumpVcs = (mode: VcsMode) => {
578-
const next = (vcsRun.get(mode) ?? 0) + 1
579-
vcsRun.set(mode, next)
580-
return next
581-
}
582-
583-
const resetVcs = (mode?: VcsMode) => {
584-
const list = mode ? [mode] : (["git", "branch"] as const)
585-
list.forEach((item) => {
586-
bumpVcs(item)
587-
vcsTask.delete(item)
588-
setVcs("diff", item, [])
589-
setVcs("ready", item, false)
590-
})
591-
}
592-
593-
const loadVcs = (mode: VcsMode, force = false) => {
594-
if (sync.project?.vcs !== "git") return Promise.resolve()
595-
if (!force && vcs.ready[mode]) return Promise.resolve()
596-
597-
if (force) {
598-
if (vcsTask.has(mode)) bumpVcs(mode)
599-
vcsTask.delete(mode)
600-
setVcs("ready", mode, false)
601-
}
602-
603-
const current = vcsTask.get(mode)
604-
if (current) return current
605-
606-
const run = bumpVcs(mode)
607-
608-
const task = sdk.client.vcs
609-
.diff({ mode })
610-
.then((result) => {
611-
if (vcsRun.get(mode) !== run) return
612-
setVcs("diff", mode, list(result.data))
613-
setVcs("ready", mode, true)
614-
})
615-
.catch((error) => {
616-
if (vcsRun.get(mode) !== run) return
617-
console.debug("[session-review] failed to load vcs diff", { mode, error })
618-
setVcs("diff", mode, [])
619-
setVcs("ready", mode, true)
620-
})
621-
.finally(() => {
622-
if (vcsTask.get(mode) === task) vcsTask.delete(mode)
623-
})
624-
625-
vcsTask.set(mode, task)
626-
return task
627-
}
628-
629-
const refreshVcs = () => {
630-
resetVcs()
631-
const mode = untrack(vcsMode)
632-
if (!mode) return
633-
if (!untrack(wantsReview)) return
634-
void loadVcs(mode, true)
635-
}
636555

637556
createComputed((prev) => {
638557
const open = desktopReviewOpen()
@@ -663,21 +582,52 @@ export default function Page() {
663582
list.push("turn")
664583
return list
665584
})
585+
const mobileChanges = createMemo(() => !isDesktop() && store.mobileTab === "changes")
586+
const wantsReview = createMemo(() =>
587+
isDesktop()
588+
? desktopFileTreeOpen() || (desktopReviewOpen() && activeTab() === "review")
589+
: store.mobileTab === "changes",
590+
)
666591
const vcsMode = createMemo<VcsMode | undefined>(() => {
667592
if (store.changes === "git" || store.changes === "branch") return store.changes
668593
})
669-
const reviewDiffs = createMemo(() => {
670-
if (store.changes === "git") return list(vcs.diff.git)
671-
if (store.changes === "branch") return list(vcs.diff.branch)
672-
return turnDiffs()
594+
const vcsKey = createMemo(
595+
() => ["session-vcs", sdk.directory, sync.data.vcs?.branch ?? "", sync.data.vcs?.default_branch ?? ""] as const,
596+
)
597+
const vcsQuery = createQuery(() => {
598+
const mode = vcsMode()
599+
const enabled = wantsReview() && sync.project?.vcs === "git"
600+
601+
return {
602+
queryKey: [...vcsKey(), mode] as const,
603+
enabled,
604+
staleTime: Number.POSITIVE_INFINITY,
605+
gcTime: 60 * 1000,
606+
queryFn: mode
607+
? () =>
608+
sdk.client.vcs
609+
.diff({ mode })
610+
.then((result) => list(result.data))
611+
.catch((error) => {
612+
console.debug("[session-review] failed to load vcs diff", { mode, error })
613+
return []
614+
})
615+
: skipToken,
616+
}
673617
})
674-
const reviewCount = createMemo(() => reviewDiffs().length)
675-
const hasReview = createMemo(() => reviewCount() > 0)
676-
const reviewReady = createMemo(() => {
677-
if (store.changes === "git") return vcs.ready.git
678-
if (store.changes === "branch") return vcs.ready.branch
618+
const refreshVcs = () => void queryClient.invalidateQueries({ queryKey: vcsKey() })
619+
const reviewDiffs = () => {
620+
if (store.changes === "git" || store.changes === "branch")
621+
// avoids suspense
622+
return vcsQuery.isFetched ? (vcsQuery.data ?? []) : []
623+
return turnDiffs()
624+
}
625+
const reviewCount = () => reviewDiffs().length
626+
const hasReview = () => reviewCount() > 0
627+
const reviewReady = () => {
628+
if (store.changes === "git" || store.changes === "branch") return !vcsQuery.isPending
679629
return true
680-
})
630+
}
681631

682632
const newSessionWorktree = createMemo(() => {
683633
if (store.newSessionWorktree === "create") return "create"
@@ -897,27 +847,6 @@ export default function Page() {
897847
),
898848
)
899849

900-
createEffect(
901-
on(
902-
() => sdk.directory,
903-
() => {
904-
resetVcs()
905-
},
906-
{ defer: true },
907-
),
908-
)
909-
910-
createEffect(
911-
on(
912-
() => [sync.data.vcs?.branch, sync.data.vcs?.default_branch] as const,
913-
(next, prev) => {
914-
if (prev === undefined || same(next, prev)) return
915-
refreshVcs()
916-
},
917-
{ defer: true },
918-
),
919-
)
920-
921850
const stopVcs = sdk.event.listen((evt) => {
922851
if (evt.details.type !== "file.watcher.updated") return
923852
const props =
@@ -1051,13 +980,6 @@ export default function Page() {
1051980
}
1052981
}
1053982

1054-
const mobileChanges = createMemo(() => !isDesktop() && store.mobileTab === "changes")
1055-
const wantsReview = createMemo(() =>
1056-
isDesktop()
1057-
? desktopFileTreeOpen() || (desktopReviewOpen() && activeTab() === "review")
1058-
: store.mobileTab === "changes",
1059-
)
1060-
1061983
createEffect(() => {
1062984
const list = changesOptions()
1063985
if (list.includes(store.changes)) return
@@ -1066,22 +988,12 @@ export default function Page() {
1066988
setStore("changes", next)
1067989
})
1068990

1069-
createEffect(() => {
1070-
const mode = vcsMode()
1071-
if (!mode) return
1072-
if (!wantsReview()) return
1073-
void loadVcs(mode)
1074-
})
1075-
1076991
createEffect(
1077992
on(
1078993
() => sync.data.session_status[params.id ?? ""]?.type,
1079994
(next, prev) => {
1080-
const mode = vcsMode()
1081-
if (!mode) return
1082-
if (!wantsReview()) return
1083995
if (next !== "idle" || prev === undefined || prev === "idle") return
1084-
void loadVcs(mode, true)
996+
refreshVcs()
1085997
},
1086998
{ defer: true },
1087999
),

0 commit comments

Comments
 (0)