diff --git a/ui/src/lib/app-router.test.tsx b/ui/src/lib/app-router.test.tsx new file mode 100644 index 00000000000..3a7edc429f3 --- /dev/null +++ b/ui/src/lib/app-router.test.tsx @@ -0,0 +1,38 @@ +// @vitest-environment jsdom + +import { flushSync } from "react-dom"; +import { createRoot, type Root } from "react-dom/client"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { RouterProvider, useBlocker } from "@/lib/router"; +import { createAppRouter } from "./app-router"; + +describe("createAppRouter", () => { + let container: HTMLDivElement; + let root: Root; + + beforeEach(() => { + window.history.replaceState(null, "", "/agents/test/configuration"); + container = document.createElement("div"); + document.body.appendChild(container); + root = createRoot(container); + }); + + afterEach(() => { + flushSync(() => root.unmount()); + container.remove(); + }); + + it("provides the data-router context required by navigation blockers", async () => { + function BlockerProbe() { + const blocker = useBlocker(true); + return {blocker.state}; + } + + const router = createAppRouter(); + + flushSync(() => root.render()); + + expect(container.textContent).toBe("unblocked"); + router.dispose(); + }); +}); diff --git a/ui/src/lib/app-router.tsx b/ui/src/lib/app-router.tsx new file mode 100644 index 00000000000..90a68dd9cd9 --- /dev/null +++ b/ui/src/lib/app-router.tsx @@ -0,0 +1,11 @@ +import type { ReactNode } from "react"; +import { createBrowserRouter } from "@/lib/router"; + +export function createAppRouter(element: ReactNode) { + return createBrowserRouter([ + { + path: "*", + element, + }, + ]); +} diff --git a/ui/src/main.tsx b/ui/src/main.tsx index 3da35e44c8b..0fa7817a20c 100644 --- a/ui/src/main.tsx +++ b/ui/src/main.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { StrictMode } from "react"; import * as ReactDOM from "react-dom"; import { createRoot } from "react-dom/client"; -import { BrowserRouter } from "@/lib/router"; +import { RouterProvider } from "@/lib/router"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { App } from "./App"; import { CompanyProvider, useCompany } from "./context/CompanyContext"; @@ -18,6 +18,7 @@ import { TooltipProvider } from "@/components/ui/tooltip"; import { initPluginBridge } from "./plugins/bridge-init"; import { PluginLauncherProvider } from "./plugins/launchers"; import { startPerfMeasureReaper } from "./lib/perf-measure-reaper"; +import { createAppRouter } from "./lib/app-router"; import "@mdxeditor/editor/style.css"; import "./index.css"; @@ -52,33 +53,35 @@ function CompanyAwareBreadcrumbProvider({ children }: { children: React.ReactNod return {children}; } +const router = createAppRouter( + + + + + + + + + + + + + + + + + + + + + , +); + createRoot(document.getElementById("root")!).render( - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/ui/src/pages/AgentDetail.tsx b/ui/src/pages/AgentDetail.tsx index c7a28d99024..ef8ac2e15b7 100644 --- a/ui/src/pages/AgentDetail.tsx +++ b/ui/src/pages/AgentDetail.tsx @@ -1061,14 +1061,6 @@ export function AgentDetail() { }); }, [resolvedAgentId, agentMembershipState]); - useBeforeUnload( - useCallback((event) => { - if (!configDirty) return; - event.preventDefault(); - event.returnValue = ""; - }, [configDirty]), - ); - if (isLoading) return ; if (error) return

{error.message}

; if (!agent) return null;