Skip to content

Commit 09ef650

Browse files
committed
refactor(app): centralize sync query options
1 parent f5c3d35 commit 09ef650

7 files changed

Lines changed: 70 additions & 43 deletions

File tree

packages/app/src/components/dialog-select-mcp.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Dialog } from "@opencode-ai/ui/dialog"
66
import { List } from "@opencode-ai/ui/list"
77
import { Switch } from "@opencode-ai/ui/switch"
88
import { useLanguage } from "@/context/language"
9-
import { mcpQueryKey } from "@/context/global-sync"
9+
import { useQueryOptions } from "@/context/global-sync"
1010

1111
const statusLabels = {
1212
connected: "mcp.status.connected",
@@ -20,6 +20,7 @@ export const DialogSelectMcp: Component = () => {
2020
const sdk = useSDK()
2121
const language = useLanguage()
2222
const queryClient = useQueryClient()
23+
const queryOptions = useQueryOptions()
2324

2425
const items = createMemo(() =>
2526
Object.entries(sync.data.mcp ?? {})
@@ -32,7 +33,7 @@ export const DialogSelectMcp: Component = () => {
3233
if (sync.data.mcp[name]?.status === "connected") await sdk.client.mcp.disconnect({ name })
3334
else await sdk.client.mcp.connect({ name })
3435
},
35-
onSuccess: () => queryClient.refetchQueries({ queryKey: mcpQueryKey(sync.directory) }),
36+
onSuccess: () => queryClient.refetchQueries({ queryKey: queryOptions.keys.mcp(sync.directory) }),
3637
}))
3738

3839
const enabledCount = createMemo(() => items().filter((i) => i.status === "connected").length)

packages/app/src/components/prompt-input.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {
1616
} from "@/context/prompt"
1717
import { useLayout } from "@/context/layout"
1818
import { useSDK } from "@/context/sdk"
19-
import { useGlobalSDK } from "@/context/global-sdk"
2019
import { useSync } from "@/context/sync"
2120
import { useComments } from "@/context/comments"
2221
import { Button } from "@opencode-ai/ui/button"
@@ -56,7 +55,7 @@ import { PromptDragOverlay } from "./prompt-input/drag-overlay"
5655
import { promptPlaceholder } from "./prompt-input/placeholder"
5756
import { ImagePreview } from "@opencode-ai/ui/image-preview"
5857
import { useQueries } from "@tanstack/solid-query"
59-
import { loadAgentsQuery, loadProvidersQuery } from "@/context/global-sync/bootstrap"
58+
import { useQueryOptions } from "@/context/global-sync"
6059

6160
interface PromptInputProps {
6261
class?: string
@@ -103,7 +102,7 @@ const NON_EMPTY_TEXT = /[^\s\u200B]/
103102

104103
export const PromptInput: Component<PromptInputProps> = (props) => {
105104
const sdk = useSDK()
106-
const globalSDK = useGlobalSDK()
105+
const queryOptions = useQueryOptions()
107106

108107
const sync = useSync()
109108
const local = useLocal()
@@ -1255,11 +1254,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
12551254
}
12561255

12571256
const [agentsQuery, globalProvidersQuery, providersQuery] = useQueries(() => ({
1258-
queries: [
1259-
loadAgentsQuery(sdk.directory, sdk.client),
1260-
loadProvidersQuery(null, globalSDK.client),
1261-
loadProvidersQuery(sdk.directory, sdk.client),
1262-
],
1257+
queries: [queryOptions.agents(sdk.directory), queryOptions.providers(null), queryOptions.providers(sdk.directory)],
12631258
}))
12641259

12651260
const agentsLoading = () => agentsQuery.isLoading

packages/app/src/components/status-popover-body.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { useSDK } from "@/context/sdk"
1515
import { normalizeServerUrl, ServerConnection, useServer } from "@/context/server"
1616
import { useSync } from "@/context/sync"
1717
import { useCheckServerHealth, type ServerHealth } from "@/utils/server-health"
18-
import { mcpQueryKey } from "@/context/global-sync"
18+
import { useQueryOptions } from "@/context/global-sync"
1919

2020
const pollMs = 10_000
2121

@@ -139,13 +139,14 @@ const useMcpToggleMutation = () => {
139139
const sdk = useSDK()
140140
const language = useLanguage()
141141
const queryClient = useQueryClient()
142+
const queryOptions = useQueryOptions()
142143

143144
return useMutation(() => ({
144145
mutationFn: async (name: string) => {
145146
const status = sync.data.mcp[name]
146147
await (status?.status === "connected" ? sdk.client.mcp.disconnect({ name }) : sdk.client.mcp.connect({ name }))
147148
},
148-
onSuccess: () => queryClient.refetchQueries({ queryKey: mcpQueryKey(sync.directory) }),
149+
onSuccess: () => queryClient.refetchQueries({ queryKey: queryOptions.keys.mcp(sync.directory) }),
149150
onError: (err) => {
150151
showToast({
151152
variant: "error",

packages/app/src/context/global-sync.tsx

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ import {
1818
bootstrapDirectory,
1919
bootstrapGlobal,
2020
clearProviderRev,
21+
loadAgentsQuery,
2122
loadGlobalConfigQuery,
2223
loadPathQuery,
24+
loadProjectsQuery,
2325
loadProvidersQuery,
2426
} from "./global-sync/bootstrap"
2527
import { createChildStoreManager } from "./global-sync/child-store"
@@ -77,12 +79,37 @@ function createGlobalSync() {
7779
const sessionLoads = new Map<string, Promise<void>>()
7880
const sessionMeta = new Map<string, { limit: number }>()
7981

82+
const sdkFor = (directory: string) => {
83+
const key = directoryKey(directory)
84+
const cached = sdkCache.get(key)
85+
if (cached) return cached
86+
const sdk = globalSDK.createClient({
87+
directory,
88+
throwOnError: true,
89+
})
90+
sdkCache.set(key, sdk)
91+
return sdk
92+
}
93+
94+
const queryOptionsApi = {
95+
globalConfig: () => loadGlobalConfigQuery(globalSDK.client),
96+
projects: () => loadProjectsQuery(globalSDK.client),
97+
providers: (directory: string | null) =>
98+
loadProvidersQuery(directory, directory === null ? globalSDK.client : sdkFor(directory)),
99+
path: (directory: string | null) =>
100+
loadPathQuery(directory, directory === null ? globalSDK.client : sdkFor(directory)),
101+
agents: (directory: string) => loadAgentsQuery(directory, sdkFor(directory)),
102+
mcp: (directory: string) => loadMcpQuery(directory, sdkFor(directory)),
103+
lsp: (directory: string) => loadLspQuery(directory, sdkFor(directory)),
104+
keys: {
105+
lsp: lspQueryKey,
106+
mcp: mcpQueryKey,
107+
sessions: loadSessionsQueryKey,
108+
},
109+
}
110+
80111
const [configQuery, providerQuery, pathQuery] = useQueries(() => ({
81-
queries: [
82-
loadGlobalConfigQuery(globalSDK.client),
83-
loadProvidersQuery(null, globalSDK.client),
84-
loadPathQuery(null, globalSDK.client),
85-
],
112+
queries: [queryOptionsApi.globalConfig(), queryOptionsApi.providers(null), queryOptionsApi.path(null)],
86113
}))
87114

88115
const [globalStore, setGlobalStore] = createStore<GlobalStore>({
@@ -181,18 +208,6 @@ function createGlobalSync() {
181208
bootstrapInstance,
182209
})
183210

184-
const sdkFor = (directory: string) => {
185-
const key = directoryKey(directory)
186-
const cached = sdkCache.get(key)
187-
if (cached) return cached
188-
const sdk = globalSDK.createClient({
189-
directory,
190-
throwOnError: true,
191-
})
192-
sdkCache.set(key, sdk)
193-
return sdk
194-
}
195-
196211
const children = createChildStoreManager({
197212
owner,
198213
isBooting: (directory) => booting.has(directory),
@@ -209,7 +224,7 @@ function createGlobalSync() {
209224
clearSessionPrefetchDirectory(key)
210225
},
211226
translate: language.t,
212-
getSdk: sdkFor,
227+
queryOptions: queryOptionsApi,
213228
global: {
214229
provider: globalStore.provider,
215230
},
@@ -368,7 +383,7 @@ function createGlobalSync() {
368383
setSessionTodo,
369384
vcsCache: children.vcsCache.get(key),
370385
loadLsp: () => {
371-
void queryClient.fetchQuery(loadLspQuery(key, sdkFor(directory)))
386+
void queryClient.fetchQuery(queryOptionsApi.lsp(key))
372387
},
373388
})
374389
})
@@ -426,6 +441,7 @@ function createGlobalSync() {
426441
},
427442
child: children.child,
428443
peek: children.peek,
444+
queryOptions: queryOptionsApi,
429445
// bootstrap,
430446
updateConfig: updateConfigMutation.mutateAsync,
431447
project: projectApi,
@@ -447,3 +463,7 @@ export function useGlobalSync() {
447463
if (!context) throw new Error("useGlobalSync must be used within GlobalSyncProvider")
448464
return context
449465
}
466+
467+
export function useQueryOptions() {
468+
return useGlobalSync().queryOptions
469+
}

packages/app/src/context/global-sync/child-store.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ describe("createChildStoreManager", () => {
2222
onBootstrap() {},
2323
onDispose() {},
2424
translate: (key) => key,
25-
getSdk: () => null!,
25+
queryOptions: {
26+
lsp: () => null!,
27+
mcp: () => null!,
28+
path: () => null!,
29+
providers: () => null!,
30+
},
2631
global: { provider: null! },
2732
})
2833

packages/app/src/context/global-sync/child-store.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createRoot, getOwner, onCleanup, runWithOwner, type Owner } from "solid-js"
22
import { createStore, type SetStoreFunction, type Store } from "solid-js/store"
33
import { Persist, persisted } from "@/utils/persist"
4-
import type { OpencodeClient, ProviderListResponse, VcsInfo } from "@opencode-ai/sdk/v2/client"
4+
import type { ProviderListResponse, VcsInfo } from "@opencode-ai/sdk/v2/client"
55
import {
66
DIR_IDLE_TTL_MS,
77
MAX_DIR_STORES,
@@ -26,7 +26,12 @@ export function createChildStoreManager(input: {
2626
onBootstrap: (directory: string) => void
2727
onDispose: (directory: string) => void
2828
translate: (key: string, vars?: Record<string, string | number>) => string
29-
getSdk: (directory: string) => OpencodeClient
29+
queryOptions: {
30+
lsp: (directory: string) => ReturnType<typeof loadLspQuery>
31+
mcp: (directory: string) => ReturnType<typeof loadMcpQuery>
32+
path: (directory: string) => ReturnType<typeof loadPathQuery>
33+
providers: (directory: string) => ReturnType<typeof loadProvidersQuery>
34+
}
3035
global: {
3136
provider: ProviderListResponse
3237
}
@@ -171,17 +176,15 @@ export function createChildStoreManager(input: {
171176

172177
const init = () =>
173178
createRoot((dispose) => {
174-
const sdk = input.getSdk(directory)
175-
176179
const initialMeta = meta[0].value
177180
const initialIcon = icon[0].value
178181

179182
const [pathQuery, mcpQuery, lspQuery, providerQuery] = useQueries(() => ({
180183
queries: [
181-
loadPathQuery(key, sdk),
182-
loadMcpQuery(key, sdk),
183-
loadLspQuery(key, sdk),
184-
loadProvidersQuery(key, sdk),
184+
input.queryOptions.path(key),
185+
input.queryOptions.mcp(key),
186+
input.queryOptions.lsp(key),
187+
input.queryOptions.providers(key),
185188
],
186189
}))
187190

packages/app/src/pages/layout/sidebar-workspace.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { Spinner } from "@opencode-ai/ui/spinner"
1414
import { Tooltip } from "@opencode-ai/ui/tooltip"
1515
import { type Session } from "@opencode-ai/sdk/v2/client"
1616
import { type LocalProject } from "@/context/layout"
17-
import { loadSessionsQueryKey, useGlobalSync } from "@/context/global-sync"
17+
import { useGlobalSync, useQueryOptions } from "@/context/global-sync"
1818
import { useLanguage } from "@/context/language"
1919
import { pathKey } from "@/utils/path-key"
2020
import { NewSessionItem, SessionItem, SessionSkeleton } from "./sidebar-items"
@@ -300,6 +300,7 @@ export const SortableWorkspace = (props: {
300300
const navigate = useNavigate()
301301
const params = useParams()
302302
const globalSync = useGlobalSync()
303+
const queryOptions = useQueryOptions()
303304
const language = useLanguage()
304305
const sortable = createSortable(props.directory)
305306
const [workspaceStore, setWorkspaceStore] = globalSync.child(props.directory, { bootstrap: false })
@@ -320,7 +321,7 @@ export const SortableWorkspace = (props: {
320321
const boot = createMemo(() => open() || active())
321322
const count = createMemo(() => sessions()?.length ?? 0)
322323
const hasMore = createMemo(() => workspaceStore.sessionTotal > count())
323-
const fetching = useIsFetching(() => ({ queryKey: loadSessionsQueryKey(props.directory) }))
324+
const fetching = useIsFetching(() => ({ queryKey: queryOptions.keys.sessions(props.directory) }))
324325
const busy = createMemo(() => props.ctx.isBusy(props.directory))
325326
const loading = () => fetching() > 0 && count() === 0
326327
const touch = createMediaQuery("(hover: none)")
@@ -446,6 +447,7 @@ export const LocalWorkspace = (props: {
446447
mobile?: boolean
447448
}): JSX.Element => {
448449
const globalSync = useGlobalSync()
450+
const queryOptions = useQueryOptions()
449451
const language = useLanguage()
450452
const workspace = createMemo(() => {
451453
const [store, setStore] = globalSync.child(props.project.worktree)
@@ -454,7 +456,7 @@ export const LocalWorkspace = (props: {
454456
const slug = createMemo(() => base64Encode(props.project.worktree))
455457
const sessions = createMemo(() => sortedRootSessions(workspace().store, props.sortNow()))
456458
const count = createMemo(() => sessions()?.length ?? 0)
457-
const fetching = useIsFetching(() => ({ queryKey: loadSessionsQueryKey(props.project.worktree) }))
459+
const fetching = useIsFetching(() => ({ queryKey: queryOptions.keys.sessions(props.project.worktree) }))
458460
const hasMore = createMemo(() => workspace().store.sessionTotal > count())
459461
const loading = () => fetching() > 0 && count() === 0
460462
const loadMore = async () => {

0 commit comments

Comments
 (0)