diff --git a/ui/index.html b/ui/index.html
index cf3ee74b9..c596c2849 100644
--- a/ui/index.html
+++ b/ui/index.html
@@ -10,7 +10,6 @@
diff --git a/ui/src/util/basePaths.spec.ts b/ui/src/util/basePaths.spec.ts
index b7d908db0..cc661e780 100644
--- a/ui/src/util/basePaths.spec.ts
+++ b/ui/src/util/basePaths.spec.ts
@@ -5,34 +5,59 @@ import {
} from "./basePaths";
vi.mock("./basePaths", async () => {
- window.base = "/example";
+ const basePath = "/example/ui";
+ // Can't use the setBase function here as this mock gets hoisted to the top of
+ // the file so gets executed before setBase exists.
+ const base = document.createElement("base");
+ base.setAttribute("href", basePath);
+ document.body.appendChild(base);
const actual = await vi.importActual("./basePaths");
return {
...actual,
- basePath: "/example/ui/",
- apiBasePath: "/example/api/v0/",
+ basePath,
};
});
+const cleanBase = () =>
+ document.querySelectorAll("base").forEach((base) => {
+ document.body.removeChild(base);
+ });
+
+const setBase = (href: string) => {
+ const base = document.createElement("base");
+ base.setAttribute("href", href);
+ document.body.appendChild(base);
+};
+
+// Clean up the base created by the mock above.
+cleanBase();
+
describe("calculateBasePath", () => {
+ afterEach(() => {
+ cleanBase();
+ });
+
it("resolves with ui path", () => {
- window.base = "/test/";
+ setBase("/test/");
const result = calculateBasePath();
expect(result).toBe("/test/");
});
it("resolves with ui path without trailing slash", () => {
- window.base = "/test";
+ setBase("/test");
+ const result = calculateBasePath();
+ expect(result).toBe("/test/");
+ });
+
+ it("handles full URL", () => {
+ setBase("http://example.com/test/");
const result = calculateBasePath();
expect(result).toBe("/test/");
});
- it("resolves with root path if the base is not provided", () => {
- if (window.base) {
- delete window.base;
- }
+ it("resolves if the base is not provided", () => {
const result = calculateBasePath();
- expect(result).toBe("/");
+ expect(result).toBe("/ui/");
});
});
@@ -48,10 +73,10 @@ describe("appendBasePath", () => {
describe("appendAPIBasePath", () => {
it("handles paths with a leading slash", () => {
- expect(appendAPIBasePath("/test")).toBe("/example/api/v0/test");
+ expect(appendAPIBasePath("/test")).toBe("/api/v0/test");
});
it("handles paths without a leading slash", () => {
- expect(appendAPIBasePath("test")).toBe("/example/api/v0/test");
+ expect(appendAPIBasePath("test")).toBe("/api/v0/test");
});
});
diff --git a/ui/src/util/basePaths.ts b/ui/src/util/basePaths.ts
index 1f9d9d8d0..d8c428fe8 100644
--- a/ui/src/util/basePaths.ts
+++ b/ui/src/util/basePaths.ts
@@ -1,25 +1,18 @@
import { removeTrailingSlash } from "util/removeTrailingSlash";
+import { getFullPath } from "./getFullPath";
type BasePath = `/${string}`;
-declare global {
- interface Window {
- base?: string;
- }
-}
-
export const calculateBasePath = (): BasePath => {
- let basePath = "";
- if ("base" in window && typeof window.base === "string") {
- basePath = window.base;
- }
- if (basePath) {
- return `${removeTrailingSlash(basePath)}/` as BasePath;
+ const basePath = document.querySelector("base")?.href;
+ const path = basePath ? getFullPath(basePath) : null;
+ if (path) {
+ return `${removeTrailingSlash(path)}/` as BasePath;
}
- return "/";
+ return "/ui/";
};
-export const basePath: BasePath = `${calculateBasePath()}ui`;
-export const apiBasePath: BasePath = `${calculateBasePath()}api/v0/`;
+export const basePath: BasePath = calculateBasePath();
+export const apiBasePath: BasePath = "/api/v0/";
export const appendBasePath = (path: string) =>
`${removeTrailingSlash(basePath)}/${path.replace(/^\//, "")}`;