diff --git a/app/__test__/ui/client/utils/AppReduced.spec.ts b/app/__test__/ui/client/utils/AppReduced.spec.ts index 1aafba9..58a7b3f 100644 --- a/app/__test__/ui/client/utils/AppReduced.spec.ts +++ b/app/__test__/ui/client/utils/AppReduced.spec.ts @@ -203,6 +203,63 @@ describe("AppReduced", () => { }); }); + describe("withBasePath - double slash fix (admin_basepath with trailing slash)", () => { + it("should not produce double slashes when admin_basepath has trailing slash", () => { + const options: BkndAdminProps["config"] = { + basepath: "/", + admin_basepath: "/admin/", + logo_return_path: "/", + }; + + appReduced = new AppReduced(mockAppJson, options); + const result = appReduced.withBasePath("/data"); + + expect(result).toBe("/admin/data"); + expect(result).not.toContain("//"); + }); + + it("should work correctly when admin_basepath has no trailing slash", () => { + const options: BkndAdminProps["config"] = { + basepath: "/", + admin_basepath: "/admin", + logo_return_path: "/", + }; + + appReduced = new AppReduced(mockAppJson, options); + const result = appReduced.withBasePath("/data"); + + expect(result).toBe("/admin/data"); + }); + + it("should handle absolute paths with admin_basepath trailing slash", () => { + const options: BkndAdminProps["config"] = { + basepath: "/", + admin_basepath: "/admin/", + logo_return_path: "/", + }; + + appReduced = new AppReduced(mockAppJson, options); + const result = appReduced.getAbsolutePath("data"); + + expect(result).toBe("~/admin/data"); + expect(result).not.toContain("//"); + }); + + it("should handle settings path with admin_basepath trailing slash", () => { + const options: BkndAdminProps["config"] = { + basepath: "/", + admin_basepath: "/admin/", + logo_return_path: "/", + }; + + appReduced = new AppReduced(mockAppJson, options); + const result = appReduced.getSettingsPath(["general"]); + + expect(result).toBe("~/admin/settings/general"); + expect(result).not.toContain("//"); + }); + }); + describe("edge cases", () => { it("should handle undefined basepath", () => { const options: BkndAdminProps["config"] = { diff --git a/app/src/modules/server/AdminController.tsx b/app/src/modules/server/AdminController.tsx index a579ebb..d7592c5 100644 --- a/app/src/modules/server/AdminController.tsx +++ b/app/src/modules/server/AdminController.tsx @@ -123,7 +123,7 @@ export class AdminController extends Controller { const obj: AdminBkndWindowContext = { user: c.get("auth")?.user, logout_route: authRoutes.logout, - admin_basepath: this.options.adminBasepath, + admin_basepath: this.options.adminBasepath.replace(/\/+$/, ""), theme: this.options.theme, logo_return_path: this.options.logoReturnPath, }; diff --git a/app/src/ui/routes/index.tsx b/app/src/ui/routes/index.tsx index 6b3a3e4..de83a07 100644 --- a/app/src/ui/routes/index.tsx +++ b/app/src/ui/routes/index.tsx @@ -33,7 +33,7 @@ export function Routes({ }) { const { theme } = useTheme(); const ctx = useBkndWindowContext(); - const actualBasePath = basePath || ctx.admin_basepath; + const actualBasePath = (basePath || ctx.admin_basepath).replace(/\/+$/, ""); return (