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 <cynarAI@users.noreply.github.com>
This commit is contained in:
parent
0d1939c775
commit
a51ba87133
@ -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 }) => {
|
test("ordinary browsers cannot use local settings", async ({ page }) => {
|
||||||
await page.goto("/desktop-settings");
|
await expect(async () => {
|
||||||
await expect(page.getByRole("alert")).toContainText("Could not open local settings");
|
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();
|
await expect(page.getByRole("button", { name: "Models", exact: true })).toBeHidden();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import {
|
|||||||
showSessionUnavailable,
|
showSessionUnavailable,
|
||||||
} from "./lib/session-gate";
|
} from "./lib/session-gate";
|
||||||
import { IntegrationSetupPage } from "./pages/IntegrationSetup";
|
import { IntegrationSetupPage } from "./pages/IntegrationSetup";
|
||||||
import { LocalSettingsPage } from "./pages/LocalSettings";
|
|
||||||
import { McpOAuthCallbackPage } from "./pages/McpOAuthCallback";
|
import { McpOAuthCallbackPage } from "./pages/McpOAuthCallback";
|
||||||
import { ShellPage } from "./pages/Shell";
|
import { ShellPage } from "./pages/Shell";
|
||||||
|
|
||||||
@ -30,9 +29,18 @@ const OnboardingPage = lazyWithRecovery("pages/Onboarding", () =>
|
|||||||
const WelcomePage = lazyWithRecovery("pages/Welcome", () =>
|
const WelcomePage = lazyWithRecovery("pages/Welcome", () =>
|
||||||
import("./pages/Welcome").then((module) => ({ default: module.WelcomePage })),
|
import("./pages/Welcome").then((module) => ({ default: module.WelcomePage })),
|
||||||
);
|
);
|
||||||
|
const LocalSettingsPage = lazyWithRecovery("pages/LocalSettings", () =>
|
||||||
|
import("./pages/LocalSettings").then((module) => ({ default: module.LocalSettingsPage })),
|
||||||
|
);
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
if (window.location.pathname === LOCAL_SETTINGS_PAGE) return <LocalSettingsPage />;
|
if (window.location.pathname === LOCAL_SETTINGS_PAGE) {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<div className="h-full bg-background" data-rakazo-app-state="loading" />}>
|
||||||
|
<LocalSettingsPage />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
return <SessionApp />;
|
return <SessionApp />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +1,31 @@
|
|||||||
import { Trans } from "@lingui/react/macro";
|
import { Trans } from "@lingui/react/macro";
|
||||||
import { Button } from "@rakazo/ui-web";
|
import { Button } from "@rakazo/ui-web";
|
||||||
import { useEffect, useState } from "react";
|
import { Suspense, useEffect, useState } from "react";
|
||||||
import { IntegrationSetup } from "../components/integrations/IntegrationSetup";
|
import { desktopBridge } from "../lib/desktop";
|
||||||
|
import { lazyWithRecovery } from "../lib/lazy-recovery";
|
||||||
import { rpc } from "../lib/rpc";
|
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() {
|
export function LocalSettingsPage() {
|
||||||
const [section, setSection] = useState<"models" | "integrations" | null>(null);
|
const [section, setSection] = useState<"models" | "integrations" | null>(null);
|
||||||
|
const hasLocalBridge = Boolean(desktopBridge()?.localSettings);
|
||||||
const [ready, setReady] = useState(false);
|
const [ready, setReady] = useState(false);
|
||||||
const [error, setError] = useState(false);
|
const [error, setError] = useState(!hasLocalBridge);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!hasLocalBridge) return;
|
||||||
void rpc.integrationSetup
|
void rpc.integrationSetup
|
||||||
.get()
|
.get()
|
||||||
.then(() => setReady(true))
|
.then(() => setReady(true))
|
||||||
.catch(() => setError(true));
|
.catch(() => setError(true));
|
||||||
}, []);
|
}, [hasLocalBridge]);
|
||||||
return (
|
return (
|
||||||
<main className="h-full overflow-auto bg-background px-6 py-12">
|
<main className="h-full overflow-auto bg-background px-6 py-12">
|
||||||
<div className="mx-auto max-w-xl space-y-6">
|
<div className="mx-auto max-w-xl space-y-6">
|
||||||
@ -43,9 +54,15 @@ export function LocalSettingsPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</nav>
|
</nav>
|
||||||
{section === "models" ? (
|
{section === "models" ? (
|
||||||
<ModelSettingsOverlay onClose={() => setSection(null)} localOwner />
|
<Suspense fallback={null}>
|
||||||
|
<ModelSettingsOverlay onClose={() => setSection(null)} localOwner />
|
||||||
|
</Suspense>
|
||||||
|
) : null}
|
||||||
|
{section === "integrations" ? (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<IntegrationSetup serverSetup managedOnly />
|
||||||
|
</Suspense>
|
||||||
) : null}
|
) : null}
|
||||||
{section === "integrations" ? <IntegrationSetup serverSetup managedOnly /> : null}
|
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user