diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx index f4cf14518c..b7f87a09cd 100644 --- a/packages/app/src/app.tsx +++ b/packages/app/src/app.tsx @@ -9,7 +9,7 @@ import { Font } from "@opencode-ai/ui/font" import { Splash } from "@opencode-ai/ui/logo" import { ThemeProvider } from "@opencode-ai/ui/theme/context" import { MetaProvider } from "@solidjs/meta" -import { type BaseRouterProps, Navigate, Route, Router, useParams, useSearchParams } from "@solidjs/router" +import { type BaseRouterProps, Navigate, Route, Router, useNavigate, useParams, useSearchParams } from "@solidjs/router" import { QueryClient, QueryClientProvider } from "@tanstack/solid-query" import { Effect } from "effect" import { @@ -32,7 +32,7 @@ import { CommandProvider, useCommand, type CommandOption } from "@/context/comma import { CommentsProvider } from "@/context/comments" import { FileProvider } from "@/context/file" import { ServerSDKProvider } from "@/context/server-sdk" -import { ServerSyncProvider } from "@/context/server-sync" +import { ServerSyncProvider, useServerSync } from "@/context/server-sync" import { GlobalProvider, useGlobal } from "@/context/global" import { HighlightsProvider } from "@/context/highlights" import { LanguageProvider, type Locale, useLanguage } from "@/context/language" @@ -52,9 +52,10 @@ import LegacyLayout from "@/pages/layout" import NewLayout from "@/pages/layout-new" import { ErrorPage } from "./pages/error" import { useCheckServerHealth } from "./utils/server-health" -import { legacySessionServer, requireServerKey, sessionHref } from "./utils/session-route" +import { legacySessionHref, legacySessionServer, requireServerKey, sessionHref } from "./utils/session-route" +import { createSessionLineage } from "@/pages/session/session-lineage" -import { SessionPage, TargetSessionRouteContent } from "@/pages/session" +import { SessionPage, SessionRouteErrorBoundary, TargetSessionRouteContent } from "@/pages/session" import { NewHome, LegacyHome } from "@/pages/home" const NewSession = lazy(() => import("@/pages/new-session")) @@ -88,10 +89,14 @@ const SessionRoute = () => { tabs.newDraft({ server: server.key, directory: sdk().directory }, search.prompt) }) - return + return ( + + + + ) } -const TargetSessionRoute = () => { +function TargetServerRoute(props: ParentProps) { const params = useParams<{ serverKey: string; id: string }>() const global = useGlobal() const conn = createMemo(() => { @@ -105,14 +110,47 @@ const TargetSessionRoute = () => { // re-resolves reactively instead); both rely on this key for server changes. - - - + {props.children} ) } +const TargetSessionRoute = () => ( + + + +) + +function LegacyTargetSessionRoute() { + const params = useParams<{ serverKey: string; id: string }>() + return ( + + + + + + ) +} + +function LegacyTargetSessionRedirect() { + const params = useParams<{ id: string }>() + const navigate = useNavigate() + const sync = useServerSync() + const current = createSessionLineage( + () => params.id, + () => sync().session.lineage, + ) + + createEffect(() => { + const directory = current()?.session.directory + if (!directory) return + navigate(legacySessionHref(directory, params.id), { replace: true }) + }) + + return null +} + // Wraps the non-draft routes. They are gated on (and keyed to) the globally selected // server via ServerKey, then provide the server-scoped shell (Permission/Layout/ // Notification/Models + the visual Layout) for that server. @@ -542,7 +580,14 @@ function Routes(props: { serverScoped?: JSX.Element }) { {routeProps.children} )} > - {} + + { + <> + + + + } + } /> @@ -550,15 +595,15 @@ function Routes(props: { serverScoped?: JSX.Element }) { - + + - ) } -function LegacyTargetSessionRoute() { +function NewLayoutLegacySessionRedirect() { const server = useServer() const tabs = useTabs() const params = useParams<{ id: string }>() diff --git a/packages/app/src/pages/home.tsx b/packages/app/src/pages/home.tsx index 762b8b2c8e..c4d84a96f8 100644 --- a/packages/app/src/pages/home.tsx +++ b/packages/app/src/pages/home.tsx @@ -35,7 +35,7 @@ import { usePlatform } from "@/context/platform" import { DateTime } from "luxon" import { useDialog } from "@opencode-ai/ui/context/dialog" import { useDirectoryPicker } from "@/components/directory-picker" -import { useSettingsCommand } from "@/components/settings-dialog" +import { useSettingsDialog } from "@/components/settings-dialog" import { DialogSelectServer, useServerManagementController } from "@/components/dialog-select-server" import { DialogServerV2 } from "@/components/settings-v2/dialog-server-v2" import { ServerConnection, serverName, useServer } from "@/context/server" @@ -267,7 +267,7 @@ export function NewHome() { const command = useCommand() const notification = useNotification() const marked = useMarked() - const openSettings = useSettingsCommand() + const openSettings = useSettingsDialog() let focusSessionSearch: (() => void) | undefined const [state, setState] = createStore({ search: "", diff --git a/packages/app/src/pages/layout-new.tsx b/packages/app/src/pages/layout-new.tsx index 329b7c56b0..f73e7b17eb 100644 --- a/packages/app/src/pages/layout-new.tsx +++ b/packages/app/src/pages/layout-new.tsx @@ -6,11 +6,13 @@ import { Titlebar, type TitlebarUpdate } from "@/components/titlebar" import { usePlatform } from "@/context/platform" import { setNavigate } from "@/utils/notification-click" import { setV2Toast, ToastRegion } from "@/utils/toast" +import { useSettingsCommand } from "@/components/settings-dialog" export default function NewLayout(props: ParentProps) { const platform = usePlatform() const navigate = useNavigate() setNavigate(navigate) + useSettingsCommand() createEffect(() => setV2Toast(true)) diff --git a/packages/app/src/pages/new-session.tsx b/packages/app/src/pages/new-session.tsx index 461be60450..7831ed8514 100644 --- a/packages/app/src/pages/new-session.tsx +++ b/packages/app/src/pages/new-session.tsx @@ -6,7 +6,6 @@ import { Tooltip } from "@opencode-ai/ui/tooltip" import { NewSessionDesignView } from "@/components/session" import { PromptInput } from "@/components/prompt-input" import { StatusPopoverV2 } from "@/components/status-popover" -import { useSettingsCommand } from "@/components/settings-dialog" import { PromptProjectAddButton, PromptProjectSelector, @@ -45,7 +44,6 @@ export default function NewSessionPage() { const [searchParams, setSearchParams] = useSearchParams<{ draftId?: string; prompt?: string }>() useComposerCommands() - useSettingsCommand() let inputRef: HTMLDivElement | undefined diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 46bd907167..84f6b01309 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -35,7 +35,7 @@ import { previewSelectedLines } from "@opencode-ai/session-ui/pierre/selection-b import { Button } from "@opencode-ai/ui/button" import { showToast } from "@/utils/toast" import { base64Encode, checksum } from "@opencode-ai/core/util/encode" -import { Navigate, useLocation, useNavigate, useParams, useSearchParams } from "@solidjs/router" +import { useLocation, useNavigate, useParams, useSearchParams } from "@solidjs/router" import { NewSessionView, SessionHeader } from "@/components/session" import { ErrorPage } from "@/pages/error" import { CommentsProvider, useComments } from "@/context/comments" @@ -56,7 +56,6 @@ import { useSync } from "@/context/sync" import { useTabs } from "@/context/tabs" import { TerminalProvider, useTerminal } from "@/context/terminal" import { PromptInput } from "@/components/prompt-input" -import { useSettingsCommand } from "@/components/settings-dialog" import { type FollowupDraft, sendFollowupDraft } from "@/components/prompt-input/submit" import { createPromptInputController, @@ -153,7 +152,7 @@ export function TargetSessionRouteContent() { ) } -function SessionRouteErrorBoundary( +export function SessionRouteErrorBoundary( props: ParentProps<{ sessionID?: string; serverKey?: ServerConnection.Key; padded?: boolean }>, ) { const settings = useSettings() @@ -221,7 +220,6 @@ function SessionErrorFallback(props: { error: unknown; sessionID?: string; serve function ResolvedTargetSessionRoute() { const params = useParams<{ serverKey: string; id: string }>() - const settings = useSettings() const tabs = useTabs() const sync = useServerSync() const serverKey = createMemo(() => requireServerKey(params.serverKey)) @@ -248,16 +246,11 @@ function ResolvedTargetSessionRoute() { the terminal. Same-workspace tab switches keep it open because warm targets resolve synchronously from the sync cache. */} - } - > - - - - - - + + + + + ) @@ -1021,7 +1014,6 @@ export default function Page() { } useComposerCommands() - useSettingsCommand() useSessionCommands({ navigateMessageByOffset, setActiveMessage,