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;