fix: respect BASE_PATH in redirects, comparisons, and cookie consent paths

This commit is contained in:
Anthony Stirling
2026-06-06 19:20:07 +01:00
parent 0dff192281
commit 9da0a0d020
10 changed files with 42 additions and 27 deletions
@@ -34,6 +34,7 @@ import CloudUploadIcon from "@mui/icons-material/CloudUpload";
import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
import RefreshIcon from "@mui/icons-material/Refresh";
import { stripBasePath } from "@app/constants/app";
import { useSharingEnabled } from "@app/hooks/useSharingEnabled";
import { useFolders } from "@app/contexts/FolderContext";
import { useFileActions } from "@app/contexts/file/fileHooks";
@@ -190,10 +191,11 @@ export default function FileManagerView() {
// Push folder selection into the URL while still on /files.
useEffect(() => {
if (!window.location.pathname.startsWith("/files")) return;
const stripped = stripBasePath(window.location.pathname);
if (!stripped.startsWith("/files")) return;
const target =
currentFolderId === null ? "/files" : `/files/${currentFolderId}`;
if (window.location.pathname !== target) {
if (stripped !== target) {
navigate(target, { replace: true });
}
}, [currentFolderId, navigate]);
@@ -23,6 +23,7 @@ import {
useUnsavedChanges,
} from "@app/contexts/UnsavedChangesContext";
import { SettingsSearchBar } from "@app/components/shared/config/SettingsSearchBar";
import { stripBasePath } from "@app/constants/app";
interface AppConfigModalProps {
opened: boolean;
@@ -82,7 +83,7 @@ const AppConfigModalInner: React.FC<AppConfigModalProps> = ({
const detail = (ev as CustomEvent).detail as { key?: NavKey } | undefined;
if (detail?.key) {
const alreadyInSettings =
window.location.pathname.startsWith("/settings");
stripBasePath(window.location.pathname).startsWith("/settings");
navigate(`/settings/${detail.key}`, {
replace: alreadyInSettings,
});
@@ -18,7 +18,7 @@ import {
useNavigationState,
useNavigationGuard,
} from "@app/contexts/NavigationContext";
import { BASE_PATH, withBasePath } from "@app/constants/app";
import { stripBasePath, withBasePath } from "@app/constants/app";
import { useRedaction, useRedactionMode } from "@app/contexts/RedactionContext";
import TextFieldsIcon from "@mui/icons-material/TextFields";
import StraightenIcon from "@mui/icons-material/Straighten";
@@ -73,17 +73,10 @@ export function useViewerWorkbenchBarButtons(
});
}, [registerImmediatePanUpdate]);
const stripBasePath = useCallback((path: string) => {
if (BASE_PATH && path.startsWith(BASE_PATH)) {
return path.slice(BASE_PATH.length) || "/";
}
return path;
}, []);
const isAnnotationsPath = useCallback(() => {
const cleanPath = stripBasePath(window.location.pathname).toLowerCase();
return cleanPath === "/annotations" || cleanPath.endsWith("/annotations");
}, [stripBasePath]);
}, []);
const [isAnnotationsActive, setIsAnnotationsActive] = useState<boolean>(() =>
isAnnotationsPath(),
+13
View File
@@ -38,3 +38,16 @@ export const absoluteWithBasePath = (path: string): string => {
const clean = path.startsWith("/") ? path : `/${path}`;
return `${window.location.origin}${BASE_PATH}${clean}`;
};
/**
* Remove the BASE_PATH prefix from a pathname so comparisons against
* bare app routes ("/login", "/files", …) work under any subpath deploy.
*/
export const stripBasePath = (pathname: string): string => {
if (!BASE_PATH) return pathname;
if (pathname === BASE_PATH) return "/";
if (pathname.startsWith(`${BASE_PATH}/`)) {
return pathname.slice(BASE_PATH.length);
}
return pathname;
};
@@ -36,14 +36,14 @@ export const useCookieConsent = ({
const mainCSS = document.createElement("link");
mainCSS.rel = "stylesheet";
mainCSS.href = `${BASE_PATH}css/cookieconsent.css`;
mainCSS.href = `${BASE_PATH}/css/cookieconsent.css`;
if (!document.querySelector(`link[href="${mainCSS.href}"]`)) {
document.head.appendChild(mainCSS);
}
const customCSS = document.createElement("link");
customCSS.rel = "stylesheet";
customCSS.href = `${BASE_PATH}css/cookieconsentCustomisation.css`;
customCSS.href = `${BASE_PATH}/css/cookieconsentCustomisation.css`;
if (!document.querySelector(`link[href="${customCSS.href}"]`)) {
document.head.appendChild(customCSS);
}
@@ -57,7 +57,7 @@ export const useCookieConsent = ({
}
const script = document.createElement("script");
script.src = `${BASE_PATH}js/thirdParty/cookieconsent.umd.js`;
script.src = `${BASE_PATH}/js/thirdParty/cookieconsent.umd.js`;
script.onload = () => {
setTimeout(() => {
const detectTheme = () => {
@@ -11,6 +11,7 @@ import {
clampText,
extractAxiosErrorMessage,
} from "@app/services/httpErrorUtils";
import { withBasePath } from "@app/constants/app";
// Module-scoped state to reduce global variable usage
const recentSpecialByEndpoint: Record<string, number> = {};
@@ -82,7 +83,7 @@ export async function handleHttpError(error: any): Promise<boolean> {
// ignore storage access failures
}
const expiredPrefix = hadStoredJwt ? "expired=true&" : "";
window.location.href = `/login?${expiredPrefix}from=${encodeURIComponent(currentLocation)}`;
window.location.href = `${withBasePath("/login")}?${expiredPrefix}from=${encodeURIComponent(currentLocation)}`;
return true; // Suppress toast since we're redirecting
}
@@ -1,4 +1,5 @@
import { NavKey } from "@app/components/shared/config/types";
import { stripBasePath, withBasePath } from "@app/constants/app";
/**
* Navigate to a specific settings section
@@ -13,8 +14,7 @@ import { NavKey } from "@app/components/shared/config/types";
* navigateToSettings('adminPremium');
*/
export function navigateToSettings(section: NavKey) {
const basePath = window.location.pathname.split("/settings")[0] || "";
const newPath = `${basePath}/settings/${section}`;
const newPath = withBasePath(`/settings/${section}`);
window.history.pushState({}, "", newPath);
// Trigger a popstate event to notify components
@@ -30,10 +30,10 @@ export function navigateToSettings(section: NavKey) {
*
* @example
* <a href={getSettingsUrl('people')}>Go to People Settings</a>
* // Returns: "/settings/people"
* // Returns: "/settings/people" (or "/bpp/settings/people" under subpath)
*/
export function getSettingsUrl(section: NavKey): string {
return `/settings/${section}`;
return withBasePath(`/settings/${section}`);
}
/**
@@ -43,7 +43,7 @@ export function getSettingsUrl(section: NavKey): string {
* @returns True if in settings (and matching specific section if provided)
*/
export function isInSettings(section?: NavKey): boolean {
const pathname = window.location.pathname;
const pathname = stripBasePath(window.location.pathname);
if (!section) {
return pathname.startsWith("/settings");