Skip to content

Commit 89aab78

Browse files
committed
fix(router): derive the router base from the served URL
History mode broke deep links on the /index.php/... URL form. Nextcloud serves the same app under BOTH /apps/stackiq/... and /index.php/apps/stackiq/..., but generateUrl() returns only the form the instance is configured for. Arriving on the other form left the path outside the router base, vue-router could not resolve it, and the catch-all redirected to '/' -- the visitor landed on the Dashboard with no error and the deep link was silently swallowed. Measured before the fix: /apps/stackiq/komplianties -> Compliance /index.php/apps/stackiq/komplianties -> Dashboard <- silently wrong Hash routing never had this: the route travelled in the fragment, so the path prefix was irrelevant. This is the one real regression the switch introduced, and it would have applied to every app in the rollout. The e2e suite navigates via /index.php/..., which is exactly how it was caught -- two index specs failed while manual browsing on the pretty URL looked fine. Now both forms resolve, with the path preserved.
1 parent 5e5631c commit 89aab78

1 file changed

Lines changed: 29 additions & 1 deletion

File tree

src/main.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,34 @@ const pageTypesProp = { ...defaultPageTypes }
130130
const customComponentsProp = { ...customComponents }
131131
const registryProp = { ...registry }
132132

133+
/**
134+
* The router base for THIS page load.
135+
*
136+
* ⚠️ `generateUrl('/apps/stackiq')` alone is not enough. Nextcloud serves the
137+
* same app under BOTH `/apps/stackiq/...` and `/index.php/apps/stackiq/...`,
138+
* but `generateUrl()` returns only the form the instance is configured for. If
139+
* a visitor arrives on the other form — a bookmark, an emailed deep link, an
140+
* integration that hardcodes `/index.php` — the path no longer starts with the
141+
* router base, vue-router cannot resolve it, and the catch-all redirects to
142+
* `/`. The user lands on the Dashboard with no error: the deep link is
143+
* silently swallowed.
144+
*
145+
* Hash routing never had this, because the route travelled in the fragment and
146+
* the path prefix was irrelevant. Measured on this app before the fix:
147+
* `/apps/stackiq/komplianties` rendered Compliance, while
148+
* `/index.php/apps/stackiq/komplianties` rendered the Dashboard — and that is
149+
* the form the e2e suite uses, which is how it was caught.
150+
*
151+
* So derive the base from the URL actually being served, falling back to
152+
* `generateUrl()` when the app segment is absent.
153+
*
154+
* @return {string} The base path vue-router should strip from the URL.
155+
*/
156+
function routerBase() {
157+
const match = window.location.pathname.match(/^(.*\/apps\/stackiq)(?:\/|$)/)
158+
return match ? match[1] : generateUrl('/apps/stackiq')
159+
}
160+
133161
/**
134162
* Resolve `@resolve:<key>` IAppConfig sentinels in `manifest.pages[].config`
135163
* (e.g. `@resolve:voorzieningen_register`) APP-SIDE, before the router and
@@ -167,7 +195,7 @@ async function bootstrap() {
167195
// /organisaties/abc-123 all return 200 with the app shell. Without
168196
// that route a deep link 404s at the SERVER on reload, which is the
169197
// reason apps fell back to hash mode (fleet #133).
170-
history: createWebHistory(generateUrl('/apps/stackiq')),
198+
history: createWebHistory(routerBase()),
171199
routes: routesFromManifest(resolvedManifest),
172200
})
173201

0 commit comments

Comments
 (0)