diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx index 25d2e3749a..42284ee2c4 100644 --- a/packages/app/src/app.tsx +++ b/packages/app/src/app.tsx @@ -47,7 +47,7 @@ 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" -import { LayoutProvider } from "@/context/layout" +import { currentRoute, LayoutProvider } from "@/context/layout" import { ModelsProvider } from "@/context/models" import { NotificationProvider } from "@/context/notification" import { PermissionProvider } from "@/context/permission" @@ -237,6 +237,44 @@ function UiI18nBridge(props: ParentProps) { return {props.children} } +function LayoutCompatibility(props: ParentProps) { + const global = useGlobal() + const location = useLocation() + const server = useServer() + const settings = useSettings() + const tabs = useTabs() + const connection = createMemo(() => { + const route = currentRoute(location.pathname, location.search) + if (route.type === "draft" && !tabs.ready()) return + const key = + route.type === "draft" + ? tabs.store.find((tab): tab is DraftTab => tab.type === "draft" && tab.draftID === route.draftID)?.server + : route.type === "home" + ? undefined + : route.server + if (!key) return server.current + return global.servers.list().find((item) => ServerConnection.key(item) === key) + }) + const protocol = createMemo(() => { + const value = connection() + if (!value) return + return global.ensureServerCtx(value).sdk.protocolKind() + }) + + createEffect(() => { + const value = protocol() + if (!value) return + settings.general.setNewLayoutRequired(value === "v2") + }) + const ready = createMemo(() => { + const value = protocol() + if (!value) return false + return settings.general.newLayoutRequired() === (value === "v2") + }) + + return {props.children} +} + declare global { interface Window { __OPENCODE__?: { @@ -558,15 +596,17 @@ export function AppInterface(props: { component={props.router ?? Router} root={(routerProps) => ( - - - - - {routerProps.children} - - - - + + + + + + {routerProps.children} + + + + + )} > diff --git a/packages/app/src/components/dialog-custom-provider.tsx b/packages/app/src/components/dialog-custom-provider.tsx index 9e04cd83ad..5db684a2da 100644 --- a/packages/app/src/components/dialog-custom-provider.tsx +++ b/packages/app/src/components/dialog-custom-provider.tsx @@ -131,6 +131,7 @@ export function CustomProviderForm(props: { autofocus?: boolean } = {}) { const saveMutation = useMutation(() => ({ mutationFn: async (result: NonNullable>) => { + if ((await serverSDK().protocol) !== "v1") throw new Error("Custom providers are unavailable on this server") const disabledProviders = serverSync().data.config.disabled_providers ?? [] const nextDisabled = disabledProviders.filter((id) => id !== result.providerID) diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index 3beb97225a..3bd4cd10cc 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -13,7 +13,7 @@ import { useLanguage } from "@/context/language" import { usePermission } from "@/context/permission" import { usePlatform, type DisplayBackend } from "@/context/platform" import { useServerSync } from "@/context/server-sync" -import { useServerSDK } from "@/context/server-sdk" +import { useServerProtocol, useServerSDK } from "@/context/server-sdk" import { useUpdaterAction } from "./updater-action" import { monoDefault, @@ -125,10 +125,12 @@ export const SettingsGeneral: Component = () => { const serverSync = useServerSync() const serverSdk = useServerSDK() + const protocol = useServerProtocol() const [shells] = createResource( - () => - serverSdk() + () => (protocol() === "v1" ? serverSdk() : undefined), + (sdk) => + sdk .client.pty.shells() .then((res) => res.data ?? []) .catch(() => [] as ShellOption[]), @@ -322,27 +324,29 @@ export const SettingsGeneral: Component = () => { - - o.value === currentShell()) ?? autoOption} + value={(o) => o.id} + label={(o) => o.label} + onSelect={(option) => { + if (!option) return + if (option.value === currentShell()) return + serverSync().updateConfig({ shell: option.value }) + }} + variant="secondary" + size="small" + triggerVariant="settings" + triggerStyle={{ "min-width": "180px" }} + /> + + void }> = (props) => const dialog = useDialog() const language = useLanguage() const serverSDK = useServerSDK() + const protocol = useServerProtocol() const serverSync = useServerSync() const providers = useProviders() const providerConnect = useProviderConnectController({ onBack: props.onBack }) @@ -83,7 +84,8 @@ const SettingsProvidersContent: Component<{ onBack?: () => void }> = (props) => return language.t("settings.providers.tag.other") } - const canDisconnect = (item: ProviderItem) => source(item) !== "env" + const canDisconnect = (item: ProviderItem) => + source(item) !== "env" && (protocol() === "v1" || !isConfigCustom(item.id)) const note = (id: string) => PROVIDER_NOTES.find((item) => item.match(id))?.key @@ -96,6 +98,7 @@ const SettingsProvidersContent: Component<{ onBack?: () => void }> = (props) => } const disableProvider = async (providerID: string, name: string) => { + if (protocol() !== "v1") return const before = serverSync().data.config.disabled_providers ?? [] const next = before.includes(providerID) ? before : [...before, providerID] serverSync().set("config", "disabled_providers", next) @@ -218,31 +221,33 @@ const SettingsProvidersContent: Component<{ onBack?: () => void }> = (props) => )} -
-
-
- - {language.t("provider.custom.title")} - {language.t("settings.providers.tag.custom")} -
- - {language.t("settings.providers.custom.description")} - -
- -
+
+
+ + {language.t("provider.custom.title")} + {language.t("settings.providers.tag.custom")} +
+ + {language.t("settings.providers.custom.description")} + +
+ + +