Răsfoiți Sursa

Fixed web view hang on html url click in Intellij IDEA 2025.x

paviko 2 luni în urmă
părinte
comite
1e251c0bd4

+ 8 - 0
hosts/IDE_BRIDGE.md

@@ -67,6 +67,7 @@ Converted usages:
 - File: `src/lib/ideBridge.ts`
   - Exposes:
     - `ideBridge.init()` – binds dispatching to `window.postMessage` and host shims
+    - `ideBridge.isInstalled()` – returns `true` when running inside an IDE host (JCEF/VSCode iframe); use to avoid `window.open()` which hangs JCEF
     - `ideBridge.send(msg)` – UI→host fire-and-forget
     - `ideBridge.request(type, payload)` – returns Promise; resolves on `{ replyTo }`
     - `ideBridge.on(handler)` – subscribe to host→UI messages
@@ -91,6 +92,13 @@ ideBridge.on((msg) => {
 
 // Request/response example
 await ideBridge.request("openFile", { path: "/p/file.ts", line: 10 })
+
+// Opening URLs safely (avoids window.open() which hangs JCEF)
+if (ideBridge.isInstalled()) {
+  ideBridge.send({ type: "openUrl", payload: { url } })
+} else {
+  window.open(url, "_blank")
+}
 ```
 
 ---

+ 1 - 0
hosts/jetbrains-plugin/changelog.html

@@ -5,6 +5,7 @@
   <li>Updated OpenCode to v1.0.121</li>
   <li>Fixed working directory as server start directory, not git root</li>
   <li>Fixed clicking on referenced file not working in Intellij IDEA 2024.x</li>
+  <li>Fixed web view hang on html url click in Intellij IDEA 2025.x</li>
 </ul>
 
 <h3>2025.11.24</h3>

+ 21 - 11
packages/opencode/webgui/src/components/MarkdownRenderer.tsx

@@ -4,6 +4,7 @@ import ReactMarkdown from "react-markdown"
 import remarkGfm from "remark-gfm"
 import type { Components, ExtraProps } from "react-markdown"
 import { CodeBlock } from "./CodeBlock"
+import { ideBridge } from "../lib/ideBridge"
 
 interface MarkdownRendererProps {
   children: string
@@ -149,17 +150,26 @@ const markdownComponents: Partial<Components> = {
     return <p className={`mb-1.5 ${styles.text} leading-relaxed`}>{props.children}</p>
   },
 
-  // Links that open in new tab
-  a: ({ href, children }) => (
-    <a
-      href={href}
-      target="_blank"
-      rel="noopener noreferrer"
-      className="text-blue-600 dark:text-blue-400 hover:underline"
-    >
-      {children}
-    </a>
-  ),
+  // Links that open in new tab (via IDE bridge when in JCEF to avoid hangs)
+  a: ({ href, children }) => {
+    const handleClick = (e: React.MouseEvent) => {
+      if (href && ideBridge.isInstalled()) {
+        e.preventDefault()
+        ideBridge.send({ type: "openUrl", payload: { url: href } })
+      }
+    }
+    return (
+      <a
+        href={href}
+        target="_blank"
+        rel="noopener noreferrer"
+        className="text-blue-600 dark:text-blue-400 hover:underline"
+        onClick={handleClick}
+      >
+        {children}
+      </a>
+    )
+  },
 
   // Tables with borders and striped rows
   table: ({ children }) => (

+ 5 - 2
packages/opencode/webgui/src/components/settings/ApiKeysTab/hooks/useOAuthFlow.ts

@@ -33,8 +33,11 @@ export function useOAuthFlow({
       const { id, url, method } = await sdk.auth.start(providerId, methodIndex, {})
 
       if (url) {
-        window.open(url, "_blank")
-        ideBridge.send({ type: "openUrl", payload: { url } })
+        if (ideBridge.isInstalled()) {
+          ideBridge.send({ type: "openUrl", payload: { url } })
+        } else {
+          window.open(url, "_blank")
+        }
       }
 
       if (method === "code") {

+ 4 - 0
packages/opencode/webgui/src/lib/ideBridge.ts

@@ -17,6 +17,10 @@ class IdeBridge {
   private pending = new Map<string, { resolve: (m: Message) => void; reject: (e: any) => void }>()
   private flushTimer: number | null = null
 
+  isInstalled(): boolean {
+    return typeof (window as any).__ideBridgeSend === "function" || (window.parent && window.parent !== window)
+  }
+
   init() {
     const onMessage = (ev: MessageEvent) => {
       const msg = ev.data as Message