diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx index a15b65cd84..fd956f0afa 100644 --- a/packages/app/src/app.tsx +++ b/packages/app/src/app.tsx @@ -286,11 +286,11 @@ function ConnectionError(props: { onRetry?: () => void; onServerSelected?: (key: ) } -function ServerKey(props: ParentProps) { +function ServerKey(props: { children: (key: ServerConnection.Key) => JSX.Element }) { const server = useServer() return ( - {props.children} + {(key) => props.children(key)} ) } @@ -310,22 +310,24 @@ export function AppInterface(props: { > - - - - {routerProps.children}} - > - - - - - - - - - + {() => ( + + + + {routerProps.children}} + > + + + + + + + + + + )} diff --git a/packages/app/src/components/dialog-select-server.tsx b/packages/app/src/components/dialog-select-server.tsx index ef62315bb5..c627deed30 100644 --- a/packages/app/src/components/dialog-select-server.tsx +++ b/packages/app/src/components/dialog-select-server.tsx @@ -8,7 +8,7 @@ import { List } from "@opencode-ai/ui/list" import { TextField } from "@opencode-ai/ui/text-field" import { useMutation } from "@tanstack/solid-query" import { showToast } from "@opencode-ai/ui/toast" -import { batch, createEffect, createMemo, createResource, For, onCleanup, Show, startTransition, untrack } from "solid-js" +import { batch, createEffect, createMemo, createResource, For, onCleanup, Show, untrack } from "solid-js" import { createStore, reconcile } from "solid-js/store" import { DialogWslServer } from "@/components/dialog-wsl-server" import { ServerHealthIndicator, ServerRow } from "@/components/server/server-row" @@ -386,28 +386,21 @@ export function DialogSelectServer(props: DialogSelectServerProps = {}) { const nextKey = ServerConnection.key(conn) const changed = server.key !== nextKey - const navigateHome = () => { - if (changed && typeof window !== "undefined" && window.history?.replaceState) { - window.history.replaceState(null, "", "/") + const navigateHome = () => props.onNavigateHome?.() + + const apply = () => { + dialog.close() + if (persist && conn.type === "http") { + server.add(conn) + navigateHome() return } - props.onNavigateHome?.() - } - const apply = () => - startTransition(() => { - dialog.close() - if (persist && conn.type === "http") { - server.add(conn) - navigateHome() - return - } - - batch(() => { - navigateHome() - server.setActive(nextKey) - }) + batch(() => { + navigateHome() + server.setActive(nextKey) }) + } if (!changed) { await apply() diff --git a/packages/app/src/components/status-popover-body.tsx b/packages/app/src/components/status-popover-body.tsx index 952e3eac64..787c91a21c 100644 --- a/packages/app/src/components/status-popover-body.tsx +++ b/packages/app/src/components/status-popover-body.tsx @@ -5,7 +5,7 @@ import { Switch } from "@opencode-ai/ui/switch" import { Tabs } from "@opencode-ai/ui/tabs" import { useMutation, useQueryClient } from "@tanstack/solid-query" import { showToast } from "@opencode-ai/ui/toast" -import { useNavigate } from "@solidjs/router" +import { useLocation, useNavigate } from "@solidjs/router" import { type Accessor, createEffect, createMemo, For, type JSXElement, onCleanup, Show } from "solid-js" import { createStore, reconcile } from "solid-js/store" import { ServerHealthIndicator, ServerRow } from "@/components/server/server-row" @@ -156,13 +156,14 @@ const useMcpToggleMutation = () => { })) } -export function StatusPopoverBody(props: { shown: Accessor }) { +export function StatusPopoverBody(props: { shown: Accessor; close?: () => void }) { const sync = useSync() const server = useServer() const platform = usePlatform() const dialog = useDialog() const language = useLanguage() const navigate = useNavigate() + const location = useLocation() const fail = (err: unknown) => { showToast({ @@ -251,8 +252,16 @@ export function StatusPopoverBody(props: { shown: Accessor }) { aria-disabled={blocked()} onClick={() => { if (blocked()) return + props.close?.() navigate("/") - queueMicrotask(() => server.setActive(key)) + const activate = () => { + if (location.pathname !== "/") { + setTimeout(activate, 16) + return + } + setTimeout(() => server.setActive(key), 0) + } + setTimeout(activate, 0) }} > diff --git a/packages/app/src/components/status-popover.tsx b/packages/app/src/components/status-popover.tsx index 6820a940b0..152cddffc8 100644 --- a/packages/app/src/components/status-popover.tsx +++ b/packages/app/src/components/status-popover.tsx @@ -58,7 +58,7 @@ export function StatusPopover() {
} > - + setShown(false)} /> diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx index 6190deb1ee..0a729a38de 100644 --- a/packages/app/src/context/global-sync.tsx +++ b/packages/app/src/context/global-sync.tsx @@ -371,11 +371,7 @@ function createGlobalSync() { onCleanup(() => { queue.dispose() }) - onCleanup(() => { - for (const directory of Object.keys(children.children)) { - children.disposeDirectory(directoryKey(directory)) - } - }) + onCleanup(children.disposeAll) onMount(() => { if (typeof requestAnimationFrame === "function") { diff --git a/packages/app/src/context/global-sync/child-store.ts b/packages/app/src/context/global-sync/child-store.ts index 0138310cdc..411102e26f 100644 --- a/packages/app/src/context/global-sync/child-store.ts +++ b/packages/app/src/context/global-sync/child-store.ts @@ -92,6 +92,22 @@ export function createChildStoreManager(input: { }) } + function disposeChild(key: DirectoryKey) { + const dispose = disposers.get(key) + if (!key || !children[key]) return false + vcsCache.delete(key) + metaCache.delete(key) + iconCache.delete(key) + lifecycle.delete(key) + disposers.delete(key) + delete children[key] + input.onDispose(key) + if (dispose) { + dispose() + } + return true + } + function disposeDirectory(directory: DirectoryKey) { const key = directory if ( @@ -106,18 +122,13 @@ export function createChildStoreManager(input: { return false } - vcsCache.delete(key) - metaCache.delete(key) - iconCache.delete(key) - lifecycle.delete(key) - const dispose = disposers.get(key) - if (dispose) { - dispose() - disposers.delete(key) + return disposeChild(key) + } + + function disposeAll() { + for (const directory of Object.keys(children)) { + disposeChild(directoryKey(directory)) } - delete children[key] - input.onDispose(key) - return true } function runEviction(skip?: string) { @@ -329,6 +340,7 @@ export function createChildStoreManager(input: { unpin, pinned, disposeDirectory, + disposeAll, runEviction, vcsCache, metaCache, diff --git a/packages/app/src/utils/solid-dnd.tsx b/packages/app/src/utils/solid-dnd.tsx index 8e30a033ae..363db50814 100644 --- a/packages/app/src/utils/solid-dnd.tsx +++ b/packages/app/src/utils/solid-dnd.tsx @@ -1,6 +1,6 @@ import { useDragDropContext } from "@thisbeyond/solid-dnd" import type { Transformer } from "@thisbeyond/solid-dnd" -import { createRoot, onCleanup, type JSXElement } from "solid-js" +import type { JSXElement } from "solid-js" type DragEvent = { draggable?: { id?: unknown } } @@ -27,20 +27,16 @@ const createAxisConstraint = (axis: "x" | "y", transformerId: string) => (): JSX if (!context) return null const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context const transformer = createTransformer(transformerId, axis) - const dispose = createRoot((dispose) => { - onDragStart((event) => { - const id = getDraggableId(event) - if (!id) return - addTransformer("draggables", id, transformer) - }) - onDragEnd((event) => { - const id = getDraggableId(event) - if (!id) return - removeTransformer("draggables", id, transformer.id) - }) - return dispose + onDragStart((event) => { + const id = getDraggableId(event) + if (!id) return + addTransformer("draggables", id, transformer) + }) + onDragEnd((event) => { + const id = getDraggableId(event) + if (!id) return + removeTransformer("draggables", id, transformer.id) }) - onCleanup(dispose) return null } diff --git a/packages/desktop-electron/src/main/index.ts b/packages/desktop-electron/src/main/index.ts index b12dcb3b17..e0e1a37e0f 100644 --- a/packages/desktop-electron/src/main/index.ts +++ b/packages/desktop-electron/src/main/index.ts @@ -87,6 +87,7 @@ setupApp() function setupApp() { ensureLoopbackNoProxy() app.commandLine.appendSwitch("proxy-bypass-list", "<-loopback>") + if (!app.isPackaged) app.commandLine.appendSwitch("remote-debugging-port", "9222") if (!app.requestSingleInstanceLock()) { app.quit()