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(/^\//, "")}`;