Skip to content

feat(router): move keepiq off hash routing to clean path URLs - #582

Merged
rubenvdlinde merged 1 commit into
developmentfrom
feat/keepiq-history-routing
Sep 1, 2026
Merged

feat(router): move keepiq off hash routing to clean path URLs#582
rubenvdlinde merged 1 commit into
developmentfrom
feat/keepiq-history-routing

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Fourth app off # routing, after stackiq (softwarecatalog#899), zaakafhandelapp (#609) and opencatalogi (#1341).

Two parts

  1. createWebHashHistorycreateWebHistory.

  2. routerBase(), derived from the URL actually being served. Nextcloud serves the app under both /apps/keepiq/... and /index.php/apps/keepiq/...; generateUrl() returns only one. Arriving on the other leaves the path outside the router base, vue-router cannot resolve it, and the catch-all redirects to / — no error, deep link silently swallowed.

    This app has the sharpest version of that problem. keepiq's share and send links (/share/link/:token, /send/:token, /share/request/:token) are handed to people outside the app, in messages and emails, in whichever URL shape the sender's client produced. A swallowed deep link there is a share that silently does nothing.

6 spec files built URLs with a hash; all now use real paths.

Verification

The vault is locked in this environment, so every route redirects to the lock screen — which is itself the proof that the router parsed the request first:

URL result
/apps/keepiq/secrets /apps/keepiq/lock?returnUrl=/secrets
/index.php/apps/keepiq/secrets /index.php/apps/keepiq/lock?returnUrl=/secrets
reload on the /index.php form 200, still on the lock path

No hash anywhere, both URL forms work, and the requested route survives into returnUrl. (/folders answers returnUrl=/ because the real route is /folders/:folderId, so the catch-all correctly claims the bare path.)

eslint exits 0 and prettier --check on the full glob (tests included) is clean; webpack compiles.

⚠️ I could not unlock the vault to exercise routes past the lock screen — no master password. The lock redirect preserving returnUrl is the strongest available proof that routing resolves before the guard fires.

Fourth app off `#` routing, after stackiq (softwarecatalog#899),
zaakafhandelapp (#609) and opencatalogi (#1341).

Two parts:

1. createWebHashHistory -> createWebHistory.

2. routerBase(), derived from the URL actually being served. Nextcloud
   serves the app under BOTH /apps/keepiq/... and
   /index.php/apps/keepiq/..., but generateUrl() returns only the form
   the instance is configured for. Arriving on the other leaves the path
   outside the router base, vue-router cannot resolve it, and the
   catch-all redirects to '/' -- no error, deep link silently swallowed.

   This app has the sharpest version of that problem: keepiq's share and
   send links (/share/link/:token, /send/:token, /share/request/:token)
   are handed to people OUTSIDE the app, in messages and emails, in
   whichever URL shape the sender's client produced. A swallowed deep
   link there is a share that silently does nothing.

6 spec files built URLs with a hash; all now use real paths.

Verified against the published @conduction/nextcloud-vue
(USE_LOCAL_LIB=false). The vault is locked in this environment, so every
route redirects to the lock screen -- which is itself the proof that the
router parsed the request first:

  /apps/keepiq/secrets            -> /apps/keepiq/lock?returnUrl=/secrets
  /index.php/apps/keepiq/secrets  -> /index.php/apps/keepiq/lock?returnUrl=/secrets
  RELOAD on the /index.php form   -> 200, still on the lock path

No hash anywhere, both URL forms work, and the requested route survives
into returnUrl. (/folders answers returnUrl=/ because the real route is
/folders/:folderId, so the catch-all correctly claims the bare path.)

eslint exits 0 and prettier --check on the FULL glob is clean.
@rubenvdlinde
rubenvdlinde merged commit e225828 into development Sep 1, 2026
6 checks passed
@rubenvdlinde
rubenvdlinde deleted the feat/keepiq-history-routing branch September 1, 2026 08:04
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/keepiq @ 981e607

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
test-l10n
format
check-l10n-js
check-schema-l10n
composer ✅ 111/111
npm ✅ 536/536
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development
Hydra gates

Quality workflow — 2026-09-01 08:16 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde added a commit that referenced this pull request Sep 1, 2026
Follow-up to #582, which turned E2E red on development. Three selectors
and one URL assertion still described hash routing:

  a[href$="#/"]      the Dashboard nav entry
  a[href$="#/lock"]  the Lock vault entry (twice)
  toHaveURL(/#\/lock$/)     and /#\/(?!lock)/ after unlock

Under history routing those match nothing, so the nav assertions failed
on 'element(s) not found' rather than on anything about navigation.

Matched as SUFFIXES rather than whole hrefs: Nextcloud serves the app as
both /apps/keepiq/... and /index.php/apps/keepiq/..., and the link
carries whichever base the page was loaded under, so pinning either would
fail on the other for a reason that is not a defect. The existing comment
already made that argument for the hash form; it now makes it for the
path form.

The post-unlock assertion is inverted rather than retargeted: it now
asserts we LEFT /lock instead of naming the destination, which varies
with the returnUrl the gate captured.

Verified: no hash href selectors and no hash URL assertions remain in
tests/; prettier --check on the full glob is clean.

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant