@@ -91,19 +91,90 @@ const SessionRoute = Object.assign(
9191
9292const TargetSessionRoute = Object . assign (
9393 ( ) => {
94- const sdk = useSDK ( )
95- const serverSDK = useServerSDK ( )
94+ const params = useParams < { serverKey : string ; id : string } > ( )
95+ const server = useServer ( )
96+ const conn = createMemo ( ( ) => {
97+ const key = requireServerKey ( params . serverKey )
98+ return server . list . find ( ( item ) => ServerConnection . key ( item ) === key )
99+ } )
100+
96101 return (
97- < Show when = { `${ serverSDK ( ) . scope } \0${ sdk ( ) . directory } ` } keyed >
98- < SessionProviders >
99- < Session />
100- </ SessionProviders >
102+ < Show when = { `${ params . serverKey } \0${ params . id } ` } keyed >
103+ < ServerSDKProvider server = { conn } >
104+ < ServerSyncProvider server = { conn } >
105+ < ResolvedTargetSessionRoute />
106+ </ ServerSyncProvider >
107+ </ ServerSDKProvider >
101108 </ Show >
102109 )
103110 } ,
104111 { preload : Session . preload } ,
105112)
106113
114+ function ResolvedTargetSessionRoute ( ) {
115+ const params = useParams < { serverKey : string ; id : string } > ( )
116+ const settings = useSettings ( )
117+ const tabs = useTabs ( )
118+ const serverSDK = useServerSDK ( )
119+ const serverKey = createMemo ( ( ) => requireServerKey ( params . serverKey ) )
120+ const resolved = useQuery ( ( ) => ( {
121+ queryKey : [ serverSDK ( ) . scope , "session-route" , params . id ] as const ,
122+ queryFn : async ( ) => {
123+ const session = ( await serverSDK ( ) . client . session . get ( { sessionID : params . id } ) ) . data !
124+ const root = await rootSession ( session , ( sessionID ) =>
125+ serverSDK ( )
126+ . client . session . get ( { sessionID } )
127+ . then ( ( result ) => result . data ! ) ,
128+ )
129+ return { session, rootID : root . id }
130+ } ,
131+ } ) )
132+ const directory = createMemo < string | undefined > ( ( prev ) => prev ?? resolved . data ?. session . directory )
133+ const targetDirectory = ( ) => directory ( ) !
134+
135+ createEffect ( ( ) => {
136+ const current = resolved . data
137+ if ( ! current ) return
138+ tabs . addSessionTab ( {
139+ server : serverKey ( ) ,
140+ sessionId : current . rootID ,
141+ } )
142+ } )
143+
144+ return (
145+ < TargetServerScopedProviders directory = { directory } sessionID = { ( ) => params . id } >
146+ < Show when = { ! resolved . error } fallback = { < ErrorPage error = { resolved . error } /> } >
147+ < Show when = { directory ( ) } >
148+ < Show
149+ when = { settings . general . newLayoutDesigns ( ) }
150+ fallback = { < Navigate href = { legacySessionHref ( directory ( ) ! , params . id ) } /> }
151+ >
152+ < SDKProvider directory = { targetDirectory } >
153+ < DirectoryDataProvider directory = { targetDirectory } server = { serverKey } >
154+ < Show when = { resolved . data && ! resolved . isPlaceholderData } >
155+ < TargetSessionPage />
156+ </ Show >
157+ </ DirectoryDataProvider >
158+ </ SDKProvider >
159+ </ Show >
160+ </ Show >
161+ </ Show >
162+ </ TargetServerScopedProviders >
163+ )
164+ }
165+
166+ function TargetSessionPage ( ) {
167+ const sdk = useSDK ( )
168+ const serverSDK = useServerSDK ( )
169+ return (
170+ < Show when = { `${ serverSDK ( ) . scope } \0${ sdk ( ) . directory } ` } keyed >
171+ < SessionProviders >
172+ < Session />
173+ </ SessionProviders >
174+ </ Show >
175+ )
176+ }
177+
107178// Wraps the non-draft routes. They are gated on (and keyed to) the globally selected
108179// server via ServerKey, then provide the server-scoped shell (Permission/Layout/
109180// Notification/Models + the visual Layout) for that server.
@@ -125,125 +196,42 @@ function LegacyServerLayout(props: ParentProps) {
125196 )
126197}
127198
128- // Wraps /new-session. It resolves the draft's target server and provides the
129- // server-scoped shell for that server — without ServerKey, so the page never depends
130- // on the globally "selected" server.
131- function TargetServerLayout ( props : ParentProps ) {
132- const server = useServer ( )
133- const tabs = useTabs ( )
134- const params = useParams < { serverKey ?: string } > ( )
135- const [ search ] = useSearchParams < { draftId ?: string } > ( )
136- const conn = createMemo ( ( ) => {
137- if ( params . serverKey ) {
138- const key = requireServerKey ( params . serverKey )
139- return server . list . find ( ( item ) => ServerConnection . key ( item ) === key )
140- }
141- const id = search . draftId
142- if ( ! id ) return undefined
143- const draft = tabs . store . find ( ( tab ) : tab is DraftTab => tab . type === "draft" && tab . draftID === id )
144- if ( ! draft ) return undefined
145- return server . list . find ( ( c ) => ServerConnection . key ( c ) === draft . server )
146- } )
147-
148- return (
149- < ServerSDKProvider server = { conn } >
150- < ServerSyncProvider server = { conn } >
151- < TargetDirectoryLayout > { props . children } </ TargetDirectoryLayout >
152- </ ServerSyncProvider >
153- </ ServerSDKProvider >
154- )
155- }
156-
157- function TargetDirectoryLayout ( props : ParentProps ) {
158- const params = useParams < { serverKey ?: string ; id ?: string } > ( )
159- const [ search ] = useSearchParams < { draftId ?: string } > ( )
160- const settings = useSettings ( )
161- const tabs = useTabs ( )
162- const serverSDK = useServerSDK ( )
163- const serverKey = createMemo ( ( ) => {
164- if ( params . serverKey ) return requireServerKey ( params . serverKey )
165- if ( ! search . draftId ) return undefined
166- return tabs . store . find ( ( tab ) : tab is DraftTab => tab . type === "draft" && tab . draftID === search . draftId ) ?. server
167- } )
168-
169- const resolved = useQuery ( ( ) => {
170- const id = params . id
171- return {
172- queryKey : [ serverSDK ( ) . scope , "session-route" , id ] as const ,
173- enabled : ! ! params . serverKey && ! ! params . id ,
174- queryFn : async ( ) => {
175- const session = ( await serverSDK ( ) . client . session . get ( { sessionID : params . id ! } ) ) . data !
176- const root = await rootSession ( session , ( sessionID ) =>
177- serverSDK ( )
178- . client . session . get ( { sessionID } )
179- . then ( ( result ) => result . data ! ) ,
180- )
181- return { session, rootID : root . id }
182- } ,
183- }
184- } )
185- const resolvedDirectory = createMemo ( ( ) => {
186- if ( params . serverKey ) return resolved . data ?. session . directory
187- if ( ! search . draftId ) return undefined
188- return tabs . store . find ( ( tab ) : tab is DraftTab => tab . type === "draft" && tab . draftID === search . draftId ) ?. directory
189- } )
190- const directory = createMemo < string | undefined > ( ( prev ) =>
191- search . draftId ? resolvedDirectory ( ) : ( prev ?? resolvedDirectory ( ) ) ,
192- )
193- const home = ( ) => ! params . serverKey && ! search . draftId
194- const targetDirectory = ( ) => directory ( ) !
195-
196- createEffect ( ( ) => {
197- const current = resolved . data
198- const key = serverKey ( )
199- if ( ! current || ! key ) return
200- tabs . addSessionTab ( {
201- server : key ,
202- sessionId : current . rootID ,
203- } )
204- } )
205-
206- return (
207- < NewServerScopedShell directory = { ( ) => ( home ( ) ? undefined : directory ( ) ) } sessionID = { ( ) => params . id } >
208- < Show when = { ! home ( ) } fallback = { props . children } >
209- < Show when = { ! resolved . error } fallback = { < ErrorPage error = { resolved . error } /> } >
210- < Show when = { directory ( ) } >
211- < Show
212- when = { ! params . serverKey || settings . general . newLayoutDesigns ( ) }
213- fallback = { < Navigate href = { legacySessionHref ( directory ( ) ! , params . id ! ) } /> }
214- >
215- < SDKProvider directory = { targetDirectory } >
216- < DirectoryDataProvider directory = { targetDirectory } server = { serverKey } >
217- < Show when = { ! params . serverKey || ( resolved . data && ! resolved . isPlaceholderData ) } >
218- { props . children }
219- </ Show >
220- </ DirectoryDataProvider >
221- </ SDKProvider >
222- </ Show >
223- </ Show >
224- </ Show >
225- </ Show >
226- </ NewServerScopedShell >
227- )
228- }
229-
230199function DraftRoute ( ) {
231200 const [ search ] = useSearchParams < { draftId ?: string } > ( )
232201 const tabs = useTabs ( )
233202 return (
234203 < Show when = { tabs . ready ( ) } >
235- < Show when = { search . draftId } keyed fallback = { < Navigate href = "/" /> } >
236- < ResolvedDraftRoute />
204+ < Show
205+ when = { tabs . store . find ( ( tab ) : tab is DraftTab => tab . type === "draft" && tab . draftID === search . draftId ) }
206+ keyed
207+ fallback = { < Navigate href = "/" /> }
208+ >
209+ { ( draft ) => < ResolvedDraftRoute draft = { draft } /> }
237210 </ Show >
238211 </ Show >
239212 )
240213}
241214
242- function ResolvedDraftRoute ( ) {
215+ function ResolvedDraftRoute ( props : { draft : DraftTab } ) {
216+ const server = useServer ( )
217+ const conn = createMemo ( ( ) => server . list . find ( ( item ) => ServerConnection . key ( item ) === props . draft . server ) )
218+ const directory = ( ) => props . draft . directory
219+ const serverKey = ( ) => props . draft . server
220+
243221 return (
244- < DraftProviders >
245- < NewSession />
246- </ DraftProviders >
222+ < ServerSDKProvider server = { conn } >
223+ < ServerSyncProvider server = { conn } >
224+ < TargetServerScopedProviders directory = { directory } >
225+ < SDKProvider directory = { directory } >
226+ < DirectoryDataProvider directory = { directory } server = { serverKey } >
227+ < DraftProviders >
228+ < NewSession />
229+ </ DraftProviders >
230+ </ DirectoryDataProvider >
231+ </ SDKProvider >
232+ </ TargetServerScopedProviders >
233+ </ ServerSyncProvider >
234+ </ ServerSDKProvider >
247235 )
248236}
249237
@@ -306,9 +294,7 @@ function SharedProviders(props: ParentProps) {
306294 )
307295}
308296
309- // Server-scoped providers plus the visual Layout (tabs/sidebar). These live inside
310- // each per-route server layout so they resolve to that route's server (selected vs
311- // draft). The Layout remounts when crossing between those groups.
297+ // Server-scoped providers shared by the legacy shell and the top-level new shell.
312298type ServerScopedShellProps = ParentProps < {
313299 directory ?: ( ) => string | undefined
314300 sessionID ?: ( ) => string | undefined
@@ -334,11 +320,23 @@ function LegacyServerScopedShell(props: ServerScopedShellProps) {
334320 )
335321}
336322
337- function NewServerScopedShell ( props : ServerScopedShellProps ) {
323+ function NewAppLayout ( props : ParentProps ) {
338324 return (
339- < ServerScopedProviders directory = { props . directory } sessionID = { props . sessionID } >
340- < NewLayout > { props . children } </ NewLayout >
341- </ ServerScopedProviders >
325+ < SelectedServerProviders >
326+ < ServerScopedProviders >
327+ < NewLayout > { props . children } </ NewLayout >
328+ </ ServerScopedProviders >
329+ </ SelectedServerProviders >
330+ )
331+ }
332+
333+ function TargetServerScopedProviders ( props : ServerScopedShellProps ) {
334+ return (
335+ < PermissionProvider directory = { props . directory } >
336+ < NotificationProvider directory = { props . directory } sessionID = { props . sessionID } >
337+ < ModelsProvider > { props . children } </ ModelsProvider >
338+ </ NotificationProvider >
339+ </ PermissionProvider >
342340 )
343341}
344342
@@ -524,11 +522,9 @@ export function AppInterface(props: {
524522 router ?: Component < BaseRouterProps >
525523 disableHealthCheck ?: boolean
526524} ) {
527- // The shared shell holds only server-agnostic providers (QueryClient + Settings/
528- // Command/Highlights) and stays mounted across every route. The server-scoped
529- // providers and the visual Layout live in the per-route layouts below, so they
530- // resolve to that route's server (selected for most routes, the draft's server for
531- // /new-session). appChildren is server-agnostic, so it renders here once.
525+ // The visual new layout lives in the router root so it remains mounted across
526+ // route changes. Draft and session routes override only their server-bound data
527+ // providers beneath it.
532528 const ServerShell = ( shellProps : ParentProps ) => (
533529 < QueryProvider >
534530 < SharedProviders >
@@ -552,7 +548,11 @@ export function AppInterface(props: {
552548 component = { props . router ?? Router }
553549 root = { ( routerProps ) => (
554550 < TabsProvider >
555- < ServerShell > { routerProps . children } </ ServerShell >
551+ < ServerShell >
552+ < Show when = { useSettings ( ) . general . newLayoutDesigns ( ) } fallback = { routerProps . children } >
553+ < NewAppLayout > { routerProps . children } </ NewAppLayout >
554+ </ Show >
555+ </ ServerShell >
556556 </ TabsProvider >
557557 ) }
558558 >
@@ -578,28 +578,20 @@ function Routes() {
578578 < Route path = "/session/:id?" component = { SessionRoute } />
579579 </ Route >
580580 </ Route >
581- < Route component = { TargetServerLayout } >
582- < Show when = { settings . general . newLayoutDesigns ( ) } >
583- {
584- < >
585- < Route path = "/" component = { NewHome } />
586- < Route path = "/:dir" component = { DirectoryLayout } >
587- < Route
588- path = "/session/:id"
589- component = { ( ) => {
590- const server = useServer ( )
591- const { id } = useParams ( )
592-
593- return < Navigate href = { `/server/${ server . key } /session/${ id } ` } />
594- } }
595- />
596- </ Route >
597- </ >
598- }
599- </ Show >
600- < Route path = "/new-session" component = { DraftRoute } />
601- < Route path = "/server/:serverKey/session/:id" component = { TargetSessionRoute } />
602- </ Route >
581+ < Show when = { settings . general . newLayoutDesigns ( ) } >
582+ < Route path = "/" component = { NewHome } />
583+ < Route
584+ path = "/:dir/session/:id"
585+ component = { ( ) => {
586+ const server = useServer ( )
587+ const { id } = useParams ( )
588+
589+ return < Navigate href = { `/server/${ server . key } /session/${ id } ` } />
590+ } }
591+ />
592+ </ Show >
593+ < Route path = "/new-session" component = { DraftRoute } />
594+ < Route path = "/server/:serverKey/session/:id" component = { TargetSessionRoute } />
603595 </ >
604596 )
605597}
0 commit comments