|
@@ -10,7 +10,7 @@ import { Splash } from "@opencode-ai/ui/logo"
|
|
|
import { ThemeProvider } from "@opencode-ai/ui/theme/context"
|
|
import { ThemeProvider } from "@opencode-ai/ui/theme/context"
|
|
|
import { MetaProvider } from "@solidjs/meta"
|
|
import { MetaProvider } from "@solidjs/meta"
|
|
|
import { type BaseRouterProps, Navigate, Route, Router, useParams, useSearchParams } from "@solidjs/router"
|
|
import { type BaseRouterProps, Navigate, Route, Router, useParams, useSearchParams } from "@solidjs/router"
|
|
|
-import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/solid-query"
|
|
|
|
|
|
|
+import { QueryClient, QueryClientProvider } from "@tanstack/solid-query"
|
|
|
import { Effect } from "effect"
|
|
import { Effect } from "effect"
|
|
|
import {
|
|
import {
|
|
|
type Component,
|
|
type Component,
|
|
@@ -32,7 +32,7 @@ import { CommentsProvider } from "@/context/comments"
|
|
|
import { FileProvider } from "@/context/file"
|
|
import { FileProvider } from "@/context/file"
|
|
|
import { ServerSDKProvider, useServerSDK } from "@/context/server-sdk"
|
|
import { ServerSDKProvider, useServerSDK } from "@/context/server-sdk"
|
|
|
import { ServerSyncProvider } from "@/context/server-sync"
|
|
import { ServerSyncProvider } from "@/context/server-sync"
|
|
|
-import { GlobalProvider } from "@/context/global"
|
|
|
|
|
|
|
+import { GlobalProvider, useGlobal } from "@/context/global"
|
|
|
import { HighlightsProvider } from "@/context/highlights"
|
|
import { HighlightsProvider } from "@/context/highlights"
|
|
|
import { LanguageProvider, type Locale, useLanguage } from "@/context/language"
|
|
import { LanguageProvider, type Locale, useLanguage } from "@/context/language"
|
|
|
import { LayoutProvider } from "@/context/layout"
|
|
import { LayoutProvider } from "@/context/layout"
|
|
@@ -53,87 +53,89 @@ import { ErrorPage } from "./pages/error"
|
|
|
import { useCheckServerHealth } from "./utils/server-health"
|
|
import { useCheckServerHealth } from "./utils/server-health"
|
|
|
import { legacySessionHref, requireServerKey, rootSession, sessionHref } from "./utils/session-route"
|
|
import { legacySessionHref, requireServerKey, rootSession, sessionHref } from "./utils/session-route"
|
|
|
|
|
|
|
|
-const LegacyHome = lazy(() => import("@/pages/home").then((module) => ({ default: module.LegacyHome })))
|
|
|
|
|
-const NewHome = lazy(() => import("@/pages/home").then((module) => ({ default: module.NewHome })))
|
|
|
|
|
-const Session = lazy(() => import("@/pages/session"))
|
|
|
|
|
|
|
+import Session from "@/pages/session"
|
|
|
|
|
+import { NewHome, LegacyHome } from "@/pages/home"
|
|
|
|
|
+
|
|
|
const NewSession = lazy(() => import("@/pages/new-session"))
|
|
const NewSession = lazy(() => import("@/pages/new-session"))
|
|
|
|
|
|
|
|
-const SessionRoute = Object.assign(
|
|
|
|
|
- () => {
|
|
|
|
|
- const settings = useSettings()
|
|
|
|
|
- const params = useParams()
|
|
|
|
|
- const [search] = useSearchParams<{ draftId?: string; prompt?: string }>()
|
|
|
|
|
- const sdk = useSDK()
|
|
|
|
|
- const server = useServer()
|
|
|
|
|
- const tabs = useTabs()
|
|
|
|
|
-
|
|
|
|
|
- if (params.id && settings.general.newLayoutDesigns()) {
|
|
|
|
|
- return <Navigate href={sessionHref(server.key, params.id)} />
|
|
|
|
|
- }
|
|
|
|
|
|
|
+const SessionRoute = () => {
|
|
|
|
|
+ const settings = useSettings()
|
|
|
|
|
+ const params = useParams()
|
|
|
|
|
+ const [search] = useSearchParams<{ draftId?: string; prompt?: string }>()
|
|
|
|
|
+ const sdk = useSDK()
|
|
|
|
|
+ const server = useServer()
|
|
|
|
|
+ const tabs = useTabs()
|
|
|
|
|
|
|
|
- // When the new layout is enabled, the legacy new-session route (/:dir/session with no id)
|
|
|
|
|
- // is replaced by a draft at /new-session?draftId=…
|
|
|
|
|
- createEffect(() => {
|
|
|
|
|
- if (!settings.general.newLayoutDesigns()) return
|
|
|
|
|
- if (params.id || search.draftId) return
|
|
|
|
|
- if (!tabs.ready() || !sdk().directory) return
|
|
|
|
|
- tabs.newDraft({ server: server.key, directory: sdk().directory }, search.prompt)
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ if (params.id && settings.general.newLayoutDesigns()) {
|
|
|
|
|
+ return <Navigate href={sessionHref(server.key, params.id)} />
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return (
|
|
|
|
|
- <SessionProviders>
|
|
|
|
|
- <Session />
|
|
|
|
|
- </SessionProviders>
|
|
|
|
|
- )
|
|
|
|
|
- },
|
|
|
|
|
- { preload: Session.preload },
|
|
|
|
|
-)
|
|
|
|
|
-
|
|
|
|
|
-const TargetSessionRoute = Object.assign(
|
|
|
|
|
- () => {
|
|
|
|
|
- const params = useParams<{ serverKey: string; id: string }>()
|
|
|
|
|
- const server = useServer()
|
|
|
|
|
- const conn = createMemo(() => {
|
|
|
|
|
- const key = requireServerKey(params.serverKey)
|
|
|
|
|
- return server.list.find((item) => ServerConnection.key(item) === key)
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ // When the new layout is enabled, the legacy new-session route (/:dir/session with no id)
|
|
|
|
|
+ // is replaced by a draft at /new-session?draftId=…
|
|
|
|
|
+ createEffect(() => {
|
|
|
|
|
+ if (!settings.general.newLayoutDesigns()) return
|
|
|
|
|
+ if (params.id || search.draftId) return
|
|
|
|
|
+ if (!tabs.ready() || !sdk().directory) return
|
|
|
|
|
+ tabs.newDraft({ server: server.key, directory: sdk().directory }, search.prompt)
|
|
|
|
|
+ })
|
|
|
|
|
|
|
|
- return (
|
|
|
|
|
- <Show when={`${params.serverKey}\0${params.id}`} keyed>
|
|
|
|
|
- <ServerSDKProvider server={conn}>
|
|
|
|
|
- <ServerSyncProvider server={conn}>
|
|
|
|
|
- <ResolvedTargetSessionRoute />
|
|
|
|
|
- </ServerSyncProvider>
|
|
|
|
|
- </ServerSDKProvider>
|
|
|
|
|
- </Show>
|
|
|
|
|
- )
|
|
|
|
|
- },
|
|
|
|
|
- { preload: Session.preload },
|
|
|
|
|
-)
|
|
|
|
|
|
|
+ return (
|
|
|
|
|
+ <SessionProviders>
|
|
|
|
|
+ <Session />
|
|
|
|
|
+ </SessionProviders>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const TargetSessionRoute = () => {
|
|
|
|
|
+ const params = useParams<{ serverKey: string; id: string }>()
|
|
|
|
|
+ const server = useServer()
|
|
|
|
|
+ const conn = createMemo(() => {
|
|
|
|
|
+ const key = requireServerKey(params.serverKey)
|
|
|
|
|
+ return server.list.find((item) => ServerConnection.key(item) === key)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Show when={`${params.serverKey}\0${params.id}`} keyed>
|
|
|
|
|
+ <ServerSDKProvider server={conn}>
|
|
|
|
|
+ <ServerSyncProvider server={conn}>
|
|
|
|
|
+ <ResolvedTargetSessionRoute />
|
|
|
|
|
+ </ServerSyncProvider>
|
|
|
|
|
+ </ServerSDKProvider>
|
|
|
|
|
+ </Show>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
function ResolvedTargetSessionRoute() {
|
|
function ResolvedTargetSessionRoute() {
|
|
|
const params = useParams<{ serverKey: string; id: string }>()
|
|
const params = useParams<{ serverKey: string; id: string }>()
|
|
|
const settings = useSettings()
|
|
const settings = useSettings()
|
|
|
const tabs = useTabs()
|
|
const tabs = useTabs()
|
|
|
|
|
+ const global = useGlobal()
|
|
|
const serverSDK = useServerSDK()
|
|
const serverSDK = useServerSDK()
|
|
|
const serverKey = createMemo(() => requireServerKey(params.serverKey))
|
|
const serverKey = createMemo(() => requireServerKey(params.serverKey))
|
|
|
- const resolved = useQuery(() => ({
|
|
|
|
|
- queryKey: [serverSDK().scope, "session-route", params.id] as const,
|
|
|
|
|
- queryFn: async () => {
|
|
|
|
|
- const session = (await serverSDK().client.session.get({ sessionID: params.id })).data!
|
|
|
|
|
|
|
+ const placement = createMemo(() => global.sessionPlacement.get(serverKey(), params.id))
|
|
|
|
|
+ const [resolved] = createResource(
|
|
|
|
|
+ () => {
|
|
|
|
|
+ if (placement()) return
|
|
|
|
|
+ return { id: params.id, sdk: serverSDK() }
|
|
|
|
|
+ },
|
|
|
|
|
+ async ({ id, sdk }) => {
|
|
|
|
|
+ const session = (await sdk.client.session.get({ sessionID: id })).data!
|
|
|
const root = await rootSession(session, (sessionID) =>
|
|
const root = await rootSession(session, (sessionID) =>
|
|
|
- serverSDK()
|
|
|
|
|
- .client.session.get({ sessionID })
|
|
|
|
|
- .then((result) => result.data!),
|
|
|
|
|
|
|
+ sdk.client.session.get({ sessionID }).then((result) => result.data!),
|
|
|
)
|
|
)
|
|
|
- return { session, rootID: root.id }
|
|
|
|
|
|
|
+ return global.sessionPlacement.set({
|
|
|
|
|
+ server: serverKey(),
|
|
|
|
|
+ leafID: session.id,
|
|
|
|
|
+ rootID: root.id,
|
|
|
|
|
+ directory: session.directory,
|
|
|
|
|
+ })
|
|
|
},
|
|
},
|
|
|
- }))
|
|
|
|
|
- const directory = createMemo<string | undefined>((prev) => prev ?? resolved.data?.session.directory)
|
|
|
|
|
|
|
+ )
|
|
|
|
|
+ const directory = createMemo(() => placement()?.directory ?? resolved()?.directory)
|
|
|
const targetDirectory = () => directory()!
|
|
const targetDirectory = () => directory()!
|
|
|
|
|
|
|
|
createEffect(() => {
|
|
createEffect(() => {
|
|
|
- const current = resolved.data
|
|
|
|
|
|
|
+ const current = placement() ?? resolved()
|
|
|
if (!current) return
|
|
if (!current) return
|
|
|
tabs.addSessionTab({
|
|
tabs.addSessionTab({
|
|
|
server: serverKey(),
|
|
server: serverKey(),
|
|
@@ -151,9 +153,7 @@ function ResolvedTargetSessionRoute() {
|
|
|
>
|
|
>
|
|
|
<SDKProvider directory={targetDirectory}>
|
|
<SDKProvider directory={targetDirectory}>
|
|
|
<DirectoryDataProvider directory={targetDirectory} server={serverKey}>
|
|
<DirectoryDataProvider directory={targetDirectory} server={serverKey}>
|
|
|
- <Show when={resolved.data && !resolved.isPlaceholderData}>
|
|
|
|
|
- <TargetSessionPage />
|
|
|
|
|
- </Show>
|
|
|
|
|
|
|
+ <TargetSessionPage />
|
|
|
</DirectoryDataProvider>
|
|
</DirectoryDataProvider>
|
|
|
</SDKProvider>
|
|
</SDKProvider>
|
|
|
</Show>
|
|
</Show>
|