diff --git a/src/main.js b/src/main.js index a8e14d76..b418e3e3 100644 --- a/src/main.js +++ b/src/main.js @@ -150,8 +150,35 @@ function routesFromManifest(manifest) { return routes } +/** + * The router base for THIS page load. + * + * ⚠️ `generateUrl('/apps/decidiq')` alone is not enough. Nextcloud serves the + * app under BOTH `/apps/decidiq/...` and `/index.php/apps/decidiq/...`, but + * `generateUrl()` returns only the form the instance is configured for. A + * visitor arriving on the other form — a bookmark, an emailed deep link, an + * integration that hardcodes `/index.php` — has a pathname the router cannot + * strip its base from. No route matches, the catch-all takes over, and they + * land on the dashboard with no error at all: the deep link is silently + * swallowed. + * + * Measured on a live instance for learniq, across all 282 of its routes: + * `/apps/learniq/courses` resolved to Courses, `/index.php/apps/learniq/courses` + * resolved to the dashboard. Every route behaved the same way, so this is not + * one broken page but every deep link in that URL form. + * + * Deriving the base from the pathname makes both forms resolve, because the + * base then always matches the URL the visitor actually arrived on. + * + * @return {string} The base path vue-router should strip from the URL. + */ +function routerBase() { + const match = window.location.pathname.match(/^(.*\/apps\/decidiq)(?:\/|$)/) + return match ? match[1] : generateUrl('/apps/decidiq') +} + const router = createRouter({ - history: createWebHistory(generateUrl('/apps/decidiq')), + history: createWebHistory(routerBase()), routes: routesFromManifest(mergedManifest), })