diff options
| author | Brendan Allan <[email protected]> | 2026-04-28 12:24:30 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-28 04:24:30 +0000 |
| commit | c8d9f7aa892ab46b9d6aa839d414451e8cd6b02a (patch) | |
| tree | b14b4355ea358fcc635df8d89162037ab470f505 /packages/app/src/context/global-sync/bootstrap.ts | |
| parent | cd7ec93cdfad5f35582c4b993eba5675da2ccd65 (diff) | |
| download | opencode-c8d9f7aa892ab46b9d6aa839d414451e8cd6b02a.tar.gz opencode-c8d9f7aa892ab46b9d6aa839d414451e8cd6b02a.zip | |
refactor(app): load sync state through TanStack Query (#23792)
Diffstat (limited to 'packages/app/src/context/global-sync/bootstrap.ts')
| -rw-r--r-- | packages/app/src/context/global-sync/bootstrap.ts | 194 |
1 files changed, 94 insertions, 100 deletions
diff --git a/packages/app/src/context/global-sync/bootstrap.ts b/packages/app/src/context/global-sync/bootstrap.ts index a83030fad..451531835 100644 --- a/packages/app/src/context/global-sync/bootstrap.ts +++ b/packages/app/src/context/global-sync/bootstrap.ts @@ -19,6 +19,7 @@ import type { State, VcsCache } from "./types" import { cmp, normalizeAgentList, normalizeProviderList } from "./utils" import { formatServerError } from "@/utils/server-errors" import { QueryClient, queryOptions, skipToken } from "@tanstack/solid-query" +import { loadMcpQuery } from "../global-sync" type GlobalStore = { ready: boolean @@ -66,6 +67,62 @@ function runAll(list: Array<() => Promise<unknown>>) { return Promise.allSettled(list.map((item) => item())) } +function showErrors(input: { + errors: unknown[] + title: string + translate: (key: string, vars?: Record<string, string | number>) => string + formatMoreCount: (count: number) => string +}) { + if (input.errors.length === 0) return + const message = formatServerError(input.errors[0], input.translate) + const more = input.errors.length > 1 ? input.formatMoreCount(input.errors.length - 1) : "" + showToast({ + variant: "error", + title: input.title, + description: message + more, + }) +} + +export const loadGlobalConfigQuery = ( + sdk?: OpencodeClient, + transform?: (x: Awaited<ReturnType<OpencodeClient["global"]["config"]["get"]>>) => void, +) => + queryOptions({ + queryKey: ["config"], + queryFn: sdk + ? () => + retry(() => + sdk.global.config.get().then((x) => { + transform?.(x) + return x.data! + }), + ) + : skipToken, + }) + +export const loadProjectsQuery = ( + sdk?: OpencodeClient, + transform?: (x: Awaited<ReturnType<OpencodeClient["project"]["list"]>>["data"]) => void, +) => + queryOptions({ + queryKey: ["project"], + queryFn: sdk + ? () => + retry(() => + sdk.project + .list() + .then((x) => { + return (x.data ?? []) + .filter((p) => !!p?.id) + .filter((p) => !!p.worktree && !p.worktree.includes("opencode-test")) + .slice() + .sort((a, b) => cmp(a.id, b.id)) + }) + .then(transform), + ) + : skipToken, + }) + export async function bootstrapGlobal(input: { globalSDK: OpencodeClient requestFailedTitle: string @@ -74,53 +131,15 @@ export async function bootstrapGlobal(input: { setGlobalStore: SetStoreFunction<GlobalStore> queryClient: QueryClient }) { - const fast = [ - () => - retry(() => - input.globalSDK.global.config.get().then((x) => { - input.setGlobalStore("config", reconcile(x.data!, { merge: false })) - }), - ), - ] - const slow = [ + () => input.queryClient.fetchQuery(loadGlobalConfigQuery(input.globalSDK)), + () => input.queryClient.fetchQuery(loadProvidersQuery(null, input.globalSDK)), + () => input.queryClient.fetchQuery(loadPathQuery(null, input.globalSDK)), () => - input.queryClient.fetchQuery({ - ...loadProvidersQuery(null), - queryFn: () => - retry(() => - input.globalSDK.provider.list().then((x) => { - input.setGlobalStore("provider", normalizeProviderList(x.data!)) - return null - }), - ), - }), - () => - retry(() => - input.globalSDK.path.get().then((x) => { - input.setGlobalStore("path", x.data!) - }), - ), - () => - retry(() => - input.globalSDK.project.list().then((x) => { - const projects = (x.data ?? []) - .filter((p) => !!p?.id) - .filter((p) => !!p.worktree && !p.worktree.includes("opencode-test")) - .slice() - .sort((a, b) => cmp(a.id, b.id)) - input.setGlobalStore("project", projects) - }), + input.queryClient.fetchQuery( + loadProjectsQuery(input.globalSDK, (data) => input.setGlobalStore("project", data ?? [])), ), ] - await runAll(fast) - // showErrors({ - // errors: errors(await runAll(fast)), - // title: input.requestFailedTitle, - // translate: input.translate, - // formatMoreCount: input.formatMoreCount, - // }) - await waitForPaint() await runAll(slow) // showErrors({ // errors: errors(), @@ -128,7 +147,6 @@ export async function bootstrapGlobal(input: { // translate: input.translate, // formatMoreCount: input.formatMoreCount, // }) - input.setGlobalStore("ready", true) } function groupBySession<T extends { id: string; sessionID: string }>(input: T[]) { @@ -179,26 +197,28 @@ function warmSessions(input: { ).then(() => undefined) } -export const loadProvidersQuery = (directory: string | null) => - queryOptions<null>({ queryKey: [directory, "providers"], queryFn: skipToken }) +export const loadProvidersQuery = (directory: string | null, sdk?: OpencodeClient) => + queryOptions({ + queryKey: [directory, "providers"], + queryFn: sdk ? () => retry(() => sdk.provider.list().then((x) => normalizeProviderList(x.data!))) : skipToken, + }) export const loadAgentsQuery = ( directory: string | null, sdk?: OpencodeClient, transform?: (x: Awaited<ReturnType<OpencodeClient["app"]["agents"]>>) => void, ) => - queryOptions<null>({ + queryOptions({ queryKey: [directory, "agents"], - queryFn: - sdk && transform - ? () => - retry(() => - sdk.app - .agents() - .then(transform) - .then(() => null), - ) - : skipToken, + queryFn: sdk + ? () => + retry(() => + sdk.app.agents().then((x) => { + transform?.(x) + return x.data! + }), + ) + : skipToken, }) export const loadPathQuery = ( @@ -208,16 +228,15 @@ export const loadPathQuery = ( ) => queryOptions<Path>({ queryKey: [directory, "path"], - queryFn: - sdk && transform - ? () => - retry(() => - sdk.path.get().then(async (x) => { - transform(x) - return x.data! - }), - ) - : skipToken, + queryFn: sdk + ? () => + retry(() => + sdk.path.get().then(async (x) => { + transform?.(x) + return x.data! + }), + ) + : skipToken, }) export async function bootstrapDirectory(input: { @@ -247,13 +266,6 @@ export async function bootstrapDirectory(input: { if (Object.keys(input.store.config).length === 0 && Object.keys(input.global.config).length > 0) { input.setStore("config", reconcile(input.global.config, { merge: false })) } - if (loading || input.store.provider.all.length === 0) { - input.setStore("provider_ready", false) - } - input.setStore("mcp_ready", false) - input.setStore("mcp", {}) - input.setStore("lsp_ready", false) - input.setStore("lsp", []) if (loading) input.setStore("status", "partial") const rev = (providerRev.get(input.directory) ?? 0) + 1 @@ -340,33 +352,15 @@ export async function bootstrapDirectory(input: { }), ), () => Promise.resolve(input.loadSessions(input.directory)), + () => input.queryClient.fetchQuery(loadMcpQuery(input.directory, input.sdk)), () => - retry(() => - input.sdk.mcp.status().then((x) => { - input.setStore("mcp", x.data!) - input.setStore("mcp_ready", true) - }), - ), - () => - input.queryClient.ensureQueryData({ - ...loadProvidersQuery(input.directory), - queryFn: () => - retry(() => input.sdk.provider.list()) - .then((x) => { - if (providerRev.get(input.directory) !== rev) return - input.setStore("provider", normalizeProviderList(x.data!)) - input.setStore("provider_ready", true) - }) - .catch((err) => { - if (providerRev.get(input.directory) !== rev) console.error("Failed to refresh provider list", err) - const project = getFilename(input.directory) - showToast({ - variant: "error", - title: input.translate("toast.project.reloadFailed.title", { project }), - description: formatServerError(err, input.translate), - }) - }) - .then(() => null), + input.queryClient.fetchQuery(loadProvidersQuery(input.directory, input.sdk)).catch((err) => { + const project = getFilename(input.directory) + showToast({ + variant: "error", + title: input.translate("toast.project.reloadFailed.title", { project }), + description: formatServerError(err, input.translate), + }) }), ].filter(Boolean) as (() => Promise<any>)[] |
