From a51ba87133766c95f190a5e7b0e14f760a28cb42 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 3 Oct 2026 21:07:41 +0000 Subject: [PATCH] fix(web): recover local settings boot when module fetch aborts Lazy-load the desktop-settings page and its heavy sections so loadWithRecovery can retry or reload after ERR_NETWORK_CHANGED. Show the no-desktop alert immediately when the bridge is absent. Co-authored-by: cynarAI --- apps/web/e2e/local-settings.spec.ts | 8 +++++-- apps/web/src/App.tsx | 12 +++++++++-- apps/web/src/pages/LocalSettings.tsx | 31 +++++++++++++++++++++------- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/apps/web/e2e/local-settings.spec.ts b/apps/web/e2e/local-settings.spec.ts index 64d1d49..fe336d3 100644 --- a/apps/web/e2e/local-settings.spec.ts +++ b/apps/web/e2e/local-settings.spec.ts @@ -75,7 +75,11 @@ test("local settings open and save integrations without an app session", async ( }); test("ordinary browsers cannot use local settings", async ({ page }) => { - await page.goto("/desktop-settings"); - await expect(page.getByRole("alert")).toContainText("Could not open local settings"); + await expect(async () => { + await page.goto("/desktop-settings", { waitUntil: "domcontentloaded" }); + await expect(page.getByRole("alert")).toContainText("Could not open local settings", { + timeout: 5_000, + }); + }).toPass({ timeout: 45_000 }); await expect(page.getByRole("button", { name: "Models", exact: true })).toBeHidden(); }); diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index 12dd355..1b14b88 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -14,7 +14,6 @@ import { showSessionUnavailable, } from "./lib/session-gate"; import { IntegrationSetupPage } from "./pages/IntegrationSetup"; -import { LocalSettingsPage } from "./pages/LocalSettings"; import { McpOAuthCallbackPage } from "./pages/McpOAuthCallback"; import { ShellPage } from "./pages/Shell"; @@ -30,9 +29,18 @@ const OnboardingPage = lazyWithRecovery("pages/Onboarding", () => const WelcomePage = lazyWithRecovery("pages/Welcome", () => import("./pages/Welcome").then((module) => ({ default: module.WelcomePage })), ); +const LocalSettingsPage = lazyWithRecovery("pages/LocalSettings", () => + import("./pages/LocalSettings").then((module) => ({ default: module.LocalSettingsPage })), +); export function App() { - if (window.location.pathname === LOCAL_SETTINGS_PAGE) return ; + if (window.location.pathname === LOCAL_SETTINGS_PAGE) { + return ( + }> + + + ); + } return ; } diff --git a/apps/web/src/pages/LocalSettings.tsx b/apps/web/src/pages/LocalSettings.tsx index 3a1e498..b5ef9d7 100644 --- a/apps/web/src/pages/LocalSettings.tsx +++ b/apps/web/src/pages/LocalSettings.tsx @@ -1,20 +1,31 @@ import { Trans } from "@lingui/react/macro"; import { Button } from "@rakazo/ui-web"; -import { useEffect, useState } from "react"; -import { IntegrationSetup } from "../components/integrations/IntegrationSetup"; +import { Suspense, useEffect, useState } from "react"; +import { desktopBridge } from "../lib/desktop"; +import { lazyWithRecovery } from "../lib/lazy-recovery"; import { rpc } from "../lib/rpc"; -import { ModelSettingsOverlay } from "./ModelSettingsOverlay"; + +const IntegrationSetup = lazyWithRecovery("integrations/IntegrationSetup", () => + import("../components/integrations/IntegrationSetup").then((module) => ({ + default: module.IntegrationSetup, + })), +); +const ModelSettingsOverlay = lazyWithRecovery("pages/ModelSettingsOverlay", () => + import("./ModelSettingsOverlay").then((module) => ({ default: module.ModelSettingsOverlay })), +); export function LocalSettingsPage() { const [section, setSection] = useState<"models" | "integrations" | null>(null); + const hasLocalBridge = Boolean(desktopBridge()?.localSettings); const [ready, setReady] = useState(false); - const [error, setError] = useState(false); + const [error, setError] = useState(!hasLocalBridge); useEffect(() => { + if (!hasLocalBridge) return; void rpc.integrationSetup .get() .then(() => setReady(true)) .catch(() => setError(true)); - }, []); + }, [hasLocalBridge]); return (
@@ -43,9 +54,15 @@ export function LocalSettingsPage() { {section === "models" ? ( - setSection(null)} localOwner /> + + setSection(null)} localOwner /> + + ) : null} + {section === "integrations" ? ( + + + ) : null} - {section === "integrations" ? : null} ) : null}