fix: open links from HTML report iframes in the system browser

Links inside the sandboxed iframe that renders a background-task/workspace
index.html did nothing on click, unlike the markdown viewer which opens links
in the browser.

Two causes: target="_blank" links were blocked by the sandbox before reaching
the window-open handler, and plain links fire will-frame-navigate (subframe),
which the app did not handle (will-navigate only covers the main frame).

- Add allow-popups to the HtmlFileViewer iframe sandbox so target="_blank"
  reaches setWindowOpenHandler, which routes to shell.openExternal.
- Handle will-frame-navigate in main, routing external subframe navigations to
  the system browser. Scoped to app://workspace frames so third-party note
  embeds (YouTube/Figma/Twitter) keep their internal navigation.
This commit is contained in:
Gagancreates 2026-06-11 01:42:17 +05:30
parent 344d30c951
commit 9d54213ed0
2 changed files with 32 additions and 7 deletions

View file

@ -253,14 +253,34 @@ function createWindow() {
return { action: "deny" };
});
// Handle navigation to external URLs (e.g., clicking a link without target="_blank")
win.webContents.on("will-navigate", (event, url) => {
// Handle navigation to external URLs (e.g., clicking a link without target="_blank").
// Returns true when the URL was external and routed to the system browser.
const routeExternalNavigation = (url: string): boolean => {
const isInternal =
url.startsWith("app://") || url.startsWith("http://localhost:5173");
if (!isInternal) {
event.preventDefault();
shell.openExternal(url);
}
if (isInternal) return false;
shell.openExternal(url);
return true;
};
win.webContents.on("will-navigate", (event, url) => {
if (routeExternalNavigation(url)) event.preventDefault();
});
// Subframe navigations (e.g. links clicked inside the sandboxed iframe that
// renders a background-task / workspace `index.html`) fire `will-frame-navigate`,
// not `will-navigate`. Route their external links to the system browser too,
// so HTML reports behave like the markdown viewer. Main-frame navigations are
// already handled by `will-navigate` above — skip them here to avoid double-open.
//
// Scope this to our own HTML viewer frames (identified by their app://workspace
// document origin). Third-party note embeds (YouTube, Figma, Twitter via the
// embed/iframe blocks) load from their own origins — leave their internal
// navigation untouched so the embeds keep working.
win.webContents.on("will-frame-navigate", (event) => {
if (event.isMainFrame) return;
if (!event.frame?.url.startsWith("app://workspace/")) return;
if (routeExternalNavigation(event.url)) event.preventDefault();
});
// Attach the embedded browser pane manager to this window.

View file

@ -110,7 +110,12 @@ export function HtmlFileViewer({ path }: HtmlFileViewerProps) {
<iframe
key={path}
src={iframeSrc}
sandbox="allow-scripts"
// `allow-popups` lets `target="_blank"` links reach the main process
// window-open handler, which routes them to the system browser. Plain
// links (same-frame navigations) are handled there via
// `will-frame-navigate`. No `allow-same-origin` — the doc stays
// origin-isolated.
sandbox="allow-scripts allow-popups"
className="h-full w-full border-0 bg-white"
title="HTML preview"
onLoad={() => setIframeLoaded(true)}