Skip to content

Commit 95013d2

Browse files
authored
fix(app): keep session routes within layouts (anomalyco#35842)
1 parent 14a5529 commit 95013d2

5 files changed

Lines changed: 69 additions & 32 deletions

File tree

packages/app/src/app.tsx

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { Font } from "@opencode-ai/ui/font"
99
import { Splash } from "@opencode-ai/ui/logo"
1010
import { ThemeProvider } from "@opencode-ai/ui/theme/context"
1111
import { MetaProvider } from "@solidjs/meta"
12-
import { type BaseRouterProps, Navigate, Route, Router, useParams, useSearchParams } from "@solidjs/router"
12+
import { type BaseRouterProps, Navigate, Route, Router, useNavigate, useParams, useSearchParams } from "@solidjs/router"
1313
import { QueryClient, QueryClientProvider } from "@tanstack/solid-query"
1414
import { Effect } from "effect"
1515
import {
@@ -32,7 +32,7 @@ import { CommandProvider, useCommand, type CommandOption } from "@/context/comma
3232
import { CommentsProvider } from "@/context/comments"
3333
import { FileProvider } from "@/context/file"
3434
import { ServerSDKProvider } from "@/context/server-sdk"
35-
import { ServerSyncProvider } from "@/context/server-sync"
35+
import { ServerSyncProvider, useServerSync } from "@/context/server-sync"
3636
import { GlobalProvider, useGlobal } from "@/context/global"
3737
import { HighlightsProvider } from "@/context/highlights"
3838
import { LanguageProvider, type Locale, useLanguage } from "@/context/language"
@@ -52,9 +52,10 @@ import LegacyLayout from "@/pages/layout"
5252
import NewLayout from "@/pages/layout-new"
5353
import { ErrorPage } from "./pages/error"
5454
import { useCheckServerHealth } from "./utils/server-health"
55-
import { legacySessionServer, requireServerKey, sessionHref } from "./utils/session-route"
55+
import { legacySessionHref, legacySessionServer, requireServerKey, sessionHref } from "./utils/session-route"
56+
import { createSessionLineage } from "@/pages/session/session-lineage"
5657

57-
import { SessionPage, TargetSessionRouteContent } from "@/pages/session"
58+
import { SessionPage, SessionRouteErrorBoundary, TargetSessionRouteContent } from "@/pages/session"
5859
import { NewHome, LegacyHome } from "@/pages/home"
5960

6061
const NewSession = lazy(() => import("@/pages/new-session"))
@@ -88,10 +89,14 @@ const SessionRoute = () => {
8889
tabs.newDraft({ server: server.key, directory: sdk().directory }, search.prompt)
8990
})
9091

91-
return <SessionPage />
92+
return (
93+
<SessionRouteErrorBoundary sessionID={params.id}>
94+
<SessionPage />
95+
</SessionRouteErrorBoundary>
96+
)
9297
}
9398

94-
const TargetSessionRoute = () => {
99+
function TargetServerRoute(props: ParentProps) {
95100
const params = useParams<{ serverKey: string; id: string }>()
96101
const global = useGlobal()
97102
const conn = createMemo(() => {
@@ -105,14 +110,47 @@ const TargetSessionRoute = () => {
105110
// re-resolves reactively instead); both rely on this key for server changes.
106111
<Show when={requireServerKey(params.serverKey)} keyed>
107112
<ServerSDKProvider server={conn}>
108-
<ServerSyncProvider server={conn}>
109-
<TargetSessionRouteContent />
110-
</ServerSyncProvider>
113+
<ServerSyncProvider server={conn}>{props.children}</ServerSyncProvider>
111114
</ServerSDKProvider>
112115
</Show>
113116
)
114117
}
115118

119+
const TargetSessionRoute = () => (
120+
<TargetServerRoute>
121+
<TargetSessionRouteContent />
122+
</TargetServerRoute>
123+
)
124+
125+
function LegacyTargetSessionRoute() {
126+
const params = useParams<{ serverKey: string; id: string }>()
127+
return (
128+
<TargetServerRoute>
129+
<SessionRouteErrorBoundary sessionID={params.id} serverKey={requireServerKey(params.serverKey)}>
130+
<LegacyTargetSessionRedirect />
131+
</SessionRouteErrorBoundary>
132+
</TargetServerRoute>
133+
)
134+
}
135+
136+
function LegacyTargetSessionRedirect() {
137+
const params = useParams<{ id: string }>()
138+
const navigate = useNavigate()
139+
const sync = useServerSync()
140+
const current = createSessionLineage(
141+
() => params.id,
142+
() => sync().session.lineage,
143+
)
144+
145+
createEffect(() => {
146+
const directory = current()?.session.directory
147+
if (!directory) return
148+
navigate(legacySessionHref(directory, params.id), { replace: true })
149+
})
150+
151+
return null
152+
}
153+
116154
// Wraps the non-draft routes. They are gated on (and keyed to) the globally selected
117155
// server via ServerKey, then provide the server-scoped shell (Permission/Layout/
118156
// Notification/Models + the visual Layout) for that server.
@@ -542,23 +580,30 @@ function Routes(props: { serverScoped?: JSX.Element }) {
542580
<LegacyServerLayout serverScoped={props.serverScoped}>{routeProps.children}</LegacyServerLayout>
543581
)}
544582
>
545-
<Show when={!settings.general.newLayoutDesigns()}>{<Route path="/" component={LegacyHome} />}</Show>
583+
<Show when={!settings.general.newLayoutDesigns()}>
584+
{
585+
<>
586+
<Route path="/" component={LegacyHome} />
587+
<Route path="/server/:serverKey/session/:id" component={LegacyTargetSessionRoute} />
588+
</>
589+
}
590+
</Show>
546591
<Route path="/:dir" component={DirectoryLayout}>
547592
<Route path="/" component={() => <Navigate href="session" />} />
548593
<Route path="/session/:id?" component={SessionRoute} />
549594
</Route>
550595
</Route>
551596
<Show when={settings.general.newLayoutDesigns()}>
552597
<Route path="/" component={NewHome} />
553-
<Route path="/:dir/session/:id" component={LegacyTargetSessionRoute} />
598+
<Route path="/:dir/session/:id" component={NewLayoutLegacySessionRedirect} />
599+
<Route path="/server/:serverKey/session/:id" component={TargetSessionRoute} />
554600
</Show>
555601
<Route path="/new-session" component={DraftRoute} />
556-
<Route path="/server/:serverKey/session/:id" component={TargetSessionRoute} />
557602
</>
558603
)
559604
}
560605

561-
function LegacyTargetSessionRoute() {
606+
function NewLayoutLegacySessionRedirect() {
562607
const server = useServer()
563608
const tabs = useTabs()
564609
const params = useParams<{ id: string }>()

packages/app/src/pages/home.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { usePlatform } from "@/context/platform"
3535
import { DateTime } from "luxon"
3636
import { useDialog } from "@opencode-ai/ui/context/dialog"
3737
import { useDirectoryPicker } from "@/components/directory-picker"
38-
import { useSettingsCommand } from "@/components/settings-dialog"
38+
import { useSettingsDialog } from "@/components/settings-dialog"
3939
import { DialogSelectServer, useServerManagementController } from "@/components/dialog-select-server"
4040
import { DialogServerV2 } from "@/components/settings-v2/dialog-server-v2"
4141
import { ServerConnection, serverName, useServer } from "@/context/server"
@@ -267,7 +267,7 @@ export function NewHome() {
267267
const command = useCommand()
268268
const notification = useNotification()
269269
const marked = useMarked()
270-
const openSettings = useSettingsCommand()
270+
const openSettings = useSettingsDialog()
271271
let focusSessionSearch: (() => void) | undefined
272272
const [state, setState] = createStore({
273273
search: "",

packages/app/src/pages/layout-new.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import { Titlebar, type TitlebarUpdate } from "@/components/titlebar"
66
import { usePlatform } from "@/context/platform"
77
import { setNavigate } from "@/utils/notification-click"
88
import { setV2Toast, ToastRegion } from "@/utils/toast"
9+
import { useSettingsCommand } from "@/components/settings-dialog"
910

1011
export default function NewLayout(props: ParentProps) {
1112
const platform = usePlatform()
1213
const navigate = useNavigate()
1314
setNavigate(navigate)
15+
useSettingsCommand()
1416

1517
createEffect(() => setV2Toast(true))
1618

packages/app/src/pages/new-session.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { Tooltip } from "@opencode-ai/ui/tooltip"
66
import { NewSessionDesignView } from "@/components/session"
77
import { PromptInput } from "@/components/prompt-input"
88
import { StatusPopoverV2 } from "@/components/status-popover"
9-
import { useSettingsCommand } from "@/components/settings-dialog"
109
import {
1110
PromptProjectAddButton,
1211
PromptProjectSelector,
@@ -45,7 +44,6 @@ export default function NewSessionPage() {
4544
const [searchParams, setSearchParams] = useSearchParams<{ draftId?: string; prompt?: string }>()
4645

4746
useComposerCommands()
48-
useSettingsCommand()
4947

5048
let inputRef: HTMLDivElement | undefined
5149

packages/app/src/pages/session.tsx

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { previewSelectedLines } from "@opencode-ai/session-ui/pierre/selection-b
3535
import { Button } from "@opencode-ai/ui/button"
3636
import { showToast } from "@/utils/toast"
3737
import { base64Encode, checksum } from "@opencode-ai/core/util/encode"
38-
import { Navigate, useLocation, useNavigate, useParams, useSearchParams } from "@solidjs/router"
38+
import { useLocation, useNavigate, useParams, useSearchParams } from "@solidjs/router"
3939
import { NewSessionView, SessionHeader } from "@/components/session"
4040
import { ErrorPage } from "@/pages/error"
4141
import { CommentsProvider, useComments } from "@/context/comments"
@@ -56,7 +56,6 @@ import { useSync } from "@/context/sync"
5656
import { useTabs } from "@/context/tabs"
5757
import { TerminalProvider, useTerminal } from "@/context/terminal"
5858
import { PromptInput } from "@/components/prompt-input"
59-
import { useSettingsCommand } from "@/components/settings-dialog"
6059
import { type FollowupDraft, sendFollowupDraft } from "@/components/prompt-input/submit"
6160
import {
6261
createPromptInputController,
@@ -153,7 +152,7 @@ export function TargetSessionRouteContent() {
153152
)
154153
}
155154

156-
function SessionRouteErrorBoundary(
155+
export function SessionRouteErrorBoundary(
157156
props: ParentProps<{ sessionID?: string; serverKey?: ServerConnection.Key; padded?: boolean }>,
158157
) {
159158
const settings = useSettings()
@@ -221,7 +220,6 @@ function SessionErrorFallback(props: { error: unknown; sessionID?: string; serve
221220

222221
function ResolvedTargetSessionRoute() {
223222
const params = useParams<{ serverKey: string; id: string }>()
224-
const settings = useSettings()
225223
const tabs = useTabs()
226224
const sync = useServerSync()
227225
const serverKey = createMemo(() => requireServerKey(params.serverKey))
@@ -248,16 +246,11 @@ function ResolvedTargetSessionRoute() {
248246
the terminal. Same-workspace tab switches keep it open because warm
249247
targets resolve synchronously from the sync cache. */}
250248
<Show when={directory()}>
251-
<Show
252-
when={settings.general.newLayoutDesigns()}
253-
fallback={<Navigate href={legacySessionHref(directory()!, params.id)} />}
254-
>
255-
<SDKProvider directory={targetDirectory}>
256-
<DirectoryDataProvider directory={targetDirectory} server={serverKey}>
257-
<TargetSessionPage />
258-
</DirectoryDataProvider>
259-
</SDKProvider>
260-
</Show>
249+
<SDKProvider directory={targetDirectory}>
250+
<DirectoryDataProvider directory={targetDirectory} server={serverKey}>
251+
<TargetSessionPage />
252+
</DirectoryDataProvider>
253+
</SDKProvider>
261254
</Show>
262255
</TargetServerScopedProviders>
263256
)
@@ -1021,7 +1014,6 @@ export default function Page() {
10211014
}
10221015

10231016
useComposerCommands()
1024-
useSettingsCommand()
10251017
useSessionCommands({
10261018
navigateMessageByOffset,
10271019
setActiveMessage,

0 commit comments

Comments
 (0)