Skip to content

Keep SPA internal target=_blank links inside the app#1272

Open
Frexxty wants to merge 1 commit into
tw93:mainfrom
Frexxty:fix/spa-internal-blank-links
Open

Keep SPA internal target=_blank links inside the app#1272
Frexxty wants to merge 1 commit into
tw93:mainfrom
Frexxty:fix/spa-internal-blank-links

Conversation

@Frexxty

@Frexxty Frexxty commented Jun 28, 2026

Copy link
Copy Markdown

Opening a project or expanding a task (the peek view) in a self-hosted Plane instance launched the system browser instead of navigating inside the Pake window. The same problem affects any single-page app that follows this pattern.

The cause is how these apps build their links. Plane (via its ControlLink component) puts target="_blank" on in-app links and then handles the click itself in JavaScript, calling preventDefault and doing client-side routing. So these are ordinary same-origin internal links that only look like "open in a new tab".

The webview opens any unhandled target="_blank" navigation in the system browser by default. To compensate, the injected link guard in event.js intercepted internal _blank links, forced a full window.location.href reload, and called stopImmediatePropagation. That stop call defeated the page's own click handler, and the click could still reach the native new-window path, so the link ended up in the browser instead of the app.

The fix: for internal target="_blank" links (when --new-window is not used), retarget the anchor to _self and let the event proceed normally. The webview no longer escalates the click to a browser window, the page's own handler still runs so the SPA navigation and peek view work as intended, and a link without any handler falls back to a normal in-app _self navigation. External _blank links, OAuth/SSO handling, and the --new-window path are all unchanged.

How it was tested

  • Reproduced and confirmed the fix against a real self-hosted Plane instance: opening projects and expanding tasks now stays in the app.
  • Updated tests/unit/event-link-guard.test.js to cover the new behavior (internal _blank retargeted to _self, no forced reload) and added a test confirming external _blank links still open in the system browser.
  • Full unit suite passes (206 tests).

Files changed

  • src-tauri/src/inject/event.js
  • tests/unit/event-link-guard.test.js
Single-page apps such as Plane mark in-app links with target="_blank" and
handle the click themselves in JS (preventDefault plus client-side routing).
The webview opens any unhandled target="_blank" navigation in the system
browser, so the injected link guard tried to compensate by forcing a full
window.location reload and calling stopImmediatePropagation on internal
_blank links.

That stop call defeated the page's own click handler, and the click could
still escape to the native new-window path, so opening a project or a task
peek view in Plane launched the system browser instead of navigating in
place.

For internal target="_blank" links without --new-window, retarget the
anchor to _self and let the event proceed. The webview no longer escalates
the click to a browser window, the page's own handler runs (so the SPA
navigation and peek view work), and links without a handler fall back to a
normal in-app _self navigation. External _blank links, OAuth/SSO, and
--new-window paths are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant