|
|
@@ -126,10 +126,10 @@ function SelectedServerProviders(props: ParentProps) {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
-function LegacyServerLayout(props: ParentProps) {
|
|
|
+function LegacyServerLayout(props: ParentProps<{ serverScoped?: JSX.Element }>) {
|
|
|
return (
|
|
|
<SelectedServerProviders>
|
|
|
- <LegacyServerScopedShell>{props.children}</LegacyServerScopedShell>
|
|
|
+ <LegacyServerScopedShell serverScoped={props.serverScoped}>{props.children}</LegacyServerScopedShell>
|
|
|
</SelectedServerProviders>
|
|
|
)
|
|
|
}
|
|
|
@@ -263,12 +263,14 @@ function DesktopCommands() {
|
|
|
type ServerScopedShellProps = ParentProps<{
|
|
|
directory?: () => string | undefined
|
|
|
sessionID?: () => string | undefined
|
|
|
+ serverScoped?: JSX.Element
|
|
|
}>
|
|
|
|
|
|
function ServerScopedProviders(props: ServerScopedShellProps) {
|
|
|
return (
|
|
|
<PermissionProvider directory={props.directory}>
|
|
|
<LayoutProvider>
|
|
|
+ {props.serverScoped}
|
|
|
<ModelsProvider directory={props.directory}>{props.children}</ModelsProvider>
|
|
|
</LayoutProvider>
|
|
|
</PermissionProvider>
|
|
|
@@ -277,16 +279,16 @@ function ServerScopedProviders(props: ServerScopedShellProps) {
|
|
|
|
|
|
function LegacyServerScopedShell(props: ServerScopedShellProps) {
|
|
|
return (
|
|
|
- <ServerScopedProviders directory={props.directory} sessionID={props.sessionID}>
|
|
|
+ <ServerScopedProviders directory={props.directory} sessionID={props.sessionID} serverScoped={props.serverScoped}>
|
|
|
<LegacyLayout>{props.children}</LegacyLayout>
|
|
|
</ServerScopedProviders>
|
|
|
)
|
|
|
}
|
|
|
|
|
|
-function NewAppLayout(props: ParentProps) {
|
|
|
+function NewAppLayout(props: ParentProps<{ serverScoped?: JSX.Element }>) {
|
|
|
return (
|
|
|
<SelectedServerProviders>
|
|
|
- <ServerScopedProviders>
|
|
|
+ <ServerScopedProviders serverScoped={props.serverScoped}>
|
|
|
<NewLayout>{props.children}</NewLayout>
|
|
|
</ServerScopedProviders>
|
|
|
</SelectedServerProviders>
|
|
|
@@ -347,7 +349,7 @@ export function AppBaseProviders(props: ParentProps<{ locale?: Locale }>) {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
-function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) {
|
|
|
+function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean; startup?: Promise<void> }>) {
|
|
|
const server = useServer()
|
|
|
const checkServerHealth = useCheckServerHealth()
|
|
|
|
|
|
@@ -376,34 +378,45 @@ function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) {
|
|
|
const checking = createMemo(
|
|
|
() => checkMode() === "blocking" && ["unresolved", "pending"].includes(startupHealthCheck.state),
|
|
|
)
|
|
|
+ const [startup] = createResource(async () => {
|
|
|
+ if (!props.startup) return true
|
|
|
+ await props.startup.catch((error) => {
|
|
|
+ console.error("[startup] startup gate failed", error)
|
|
|
+ })
|
|
|
+ return true
|
|
|
+ })
|
|
|
+ const startupChecking = createMemo(
|
|
|
+ () => startupHealthCheck.latest === true && ["unresolved", "pending"].includes(startup.state),
|
|
|
+ )
|
|
|
+ const loading = createMemo(() => checking() || startupChecking())
|
|
|
|
|
|
return (
|
|
|
- <Show
|
|
|
- when={!checking()}
|
|
|
- fallback={
|
|
|
- <div class="h-dvh w-screen flex flex-col items-center justify-center bg-background-base">
|
|
|
+ <>
|
|
|
+ <Show when={!checking()}>
|
|
|
+ <Show
|
|
|
+ when={startupHealthCheck.latest}
|
|
|
+ fallback={
|
|
|
+ <ConnectionError
|
|
|
+ onRetry={() => {
|
|
|
+ if (checkMode() === "background") void healthCheckActions.refetch()
|
|
|
+ }}
|
|
|
+ onServerSelected={(key) => {
|
|
|
+ setCheckMode("blocking")
|
|
|
+ server.setActive(key)
|
|
|
+ void healthCheckActions.refetch()
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {props.children}
|
|
|
+ </Show>
|
|
|
+ </Show>
|
|
|
+ <Show when={loading()}>
|
|
|
+ <div class="fixed inset-0 z-[9999] flex flex-col items-center justify-center bg-background-base">
|
|
|
<Splash class="w-16 h-20 opacity-50 animate-pulse" />
|
|
|
</div>
|
|
|
- }
|
|
|
- >
|
|
|
- <Show
|
|
|
- when={startupHealthCheck.latest}
|
|
|
- fallback={
|
|
|
- <ConnectionError
|
|
|
- onRetry={() => {
|
|
|
- if (checkMode() === "background") void healthCheckActions.refetch()
|
|
|
- }}
|
|
|
- onServerSelected={(key) => {
|
|
|
- setCheckMode("blocking")
|
|
|
- server.setActive(key)
|
|
|
- void healthCheckActions.refetch()
|
|
|
- }}
|
|
|
- />
|
|
|
- }
|
|
|
- >
|
|
|
- {props.children}
|
|
|
</Show>
|
|
|
- </Show>
|
|
|
+ </>
|
|
|
)
|
|
|
}
|
|
|
|
|
|
@@ -470,6 +483,8 @@ export function AppInterface(props: {
|
|
|
servers?: Array<ServerConnection.Any>
|
|
|
router?: Component<BaseRouterProps>
|
|
|
disableHealthCheck?: boolean
|
|
|
+ startup?: Promise<void>
|
|
|
+ serverScoped?: JSX.Element
|
|
|
}) {
|
|
|
// The visual new layout lives in the router root so it remains mounted across
|
|
|
// route changes. Draft and session routes override only their server-bound data
|
|
|
@@ -491,7 +506,7 @@ export function AppInterface(props: {
|
|
|
>
|
|
|
<GlobalProvider>
|
|
|
<SettingsProvider>
|
|
|
- <ConnectionGate disableHealthCheck={props.disableHealthCheck}>
|
|
|
+ <ConnectionGate disableHealthCheck={props.disableHealthCheck} startup={props.startup}>
|
|
|
<Show when={useSettings().general.newLayoutDesigns().toString()} keyed>
|
|
|
<Dynamic
|
|
|
component={props.router ?? Router}
|
|
|
@@ -500,14 +515,14 @@ export function AppInterface(props: {
|
|
|
<NotificationProvider>
|
|
|
<ServerShell>
|
|
|
<Show when={useSettings().general.newLayoutDesigns()} fallback={routerProps.children}>
|
|
|
- <NewAppLayout>{routerProps.children}</NewAppLayout>
|
|
|
+ <NewAppLayout serverScoped={props.serverScoped}>{routerProps.children}</NewAppLayout>
|
|
|
</Show>
|
|
|
</ServerShell>
|
|
|
</NotificationProvider>
|
|
|
</TabsProvider>
|
|
|
)}
|
|
|
>
|
|
|
- <Routes />
|
|
|
+ <Routes serverScoped={props.serverScoped} />
|
|
|
</Dynamic>
|
|
|
</Show>
|
|
|
</ConnectionGate>
|
|
|
@@ -517,12 +532,16 @@ export function AppInterface(props: {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
-function Routes() {
|
|
|
+function Routes(props: { serverScoped?: JSX.Element }) {
|
|
|
const settings = useSettings()
|
|
|
|
|
|
return (
|
|
|
<>
|
|
|
- <Route component={LegacyServerLayout}>
|
|
|
+ <Route
|
|
|
+ component={(routeProps) => (
|
|
|
+ <LegacyServerLayout serverScoped={props.serverScoped}>{routeProps.children}</LegacyServerLayout>
|
|
|
+ )}
|
|
|
+ >
|
|
|
<Show when={!settings.general.newLayoutDesigns()}>{<Route path="/" component={LegacyHome} />}</Show>
|
|
|
<Route path="/:dir" component={DirectoryLayout}>
|
|
|
<Route path="/" component={() => <Navigate href="session" />} />
|