[codex] Handle browser passthrough during v2 resize#3744
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughCentralizes pointer-event passthrough into named interaction claims (window-drag, resize sources) tracked by the browser runtime registry; workspace and sidebar emit resize interaction state into the registry; registry computes effective passthrough, applies pointerEvents only on state transitions, and clears claims on window blur. Changes
Sequence DiagramsequenceDiagram
participant User
participant Workspace
participant Page
participant Window
participant Registry as BrowserRuntimeRegistry
participant Webview
User->>Workspace: start split-resize (drag)
Workspace->>Page: onInteractionStateChange({resizeActive:true})
Page->>Registry: setShellInteractionPassthrough(true)
User->>Window: pointer events (drag)
Window->>Registry: add/remove drag claim / blur clears claims
Registry->>Registry: compute effective passthrough
Registry->>Webview: applyPointerPassthrough() (update pointerEvents if changed)
User->>Workspace: end drag
Workspace->>Page: onInteractionStateChange({resizeActive:false})
Page->>Registry: setShellInteractionPassthrough(false)
Registry->>Registry: compute effective passthrough
Registry->>Webview: applyPointerPassthrough() (restore pointerEvents)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR introduces per-reason passthrough tracking ( Confidence Score: 5/5Safe to merge; all remaining findings are P2 style suggestions that do not block correct behavior in the common case. The multi-reason passthrough logic is correct and idempotent, the new public API is minimal, prop threading is clean, and the unmount cleanup guard is present. The one flagged concern (blur capture mode) is a theoretical edge case unlikely to trigger during normal mouse-drag operations. browserRuntimeRegistry.ts — specifically the blur capture mode in installGlobalListeners.
|
| Filename | Overview |
|---|---|
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts | Core change: introduces PassthroughReason set to track independent drag/resize passthrough sources. Adds setResizePassthrough public API, applyInteractionPassthrough on attach, and a blur safety-net listener; the blur listener uses useCapture: true which may clear passthrough mid-drag if any DOM element loses focus. |
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsx | Wires setBrowserResizePassthrough into both the workspace split-resize handle and the sidebar ResizableHandle; cleanup useEffect correctly clears the state on unmount. |
| packages/panes/src/react/components/Workspace/Workspace.tsx | Minimal change: threads onResizeDragging prop from WorkspaceProps down to the Tab component. |
| packages/panes/src/react/components/Workspace/components/Tab/Tab.tsx | Threads onResizeDragging through Tab → LayoutNodeView → SplitView and binds it to every ResizableHandle onDragging within the split-pane tree. |
| packages/panes/src/react/types.ts | Adds optional onResizeDragging?: (isDragging: boolean) => void to WorkspaceProps; backwards-compatible addition. |
Sequence Diagram
sequenceDiagram
participant User
participant ResizableHandle
participant page.tsx
participant browserRuntimeRegistry
participant Webview
User->>ResizableHandle: pointerdown (start drag)
ResizableHandle->>page.tsx: onDragging(true)
page.tsx->>browserRuntimeRegistry: setResizePassthrough(true)
browserRuntimeRegistry->>browserRuntimeRegistry: passthroughReasons.add("resize")
browserRuntimeRegistry->>Webview: pointerEvents = "none"
User->>ResizableHandle: pointermove (drag over webview)
Note over Webview: pointer events disabled — resize keeps control
User->>ResizableHandle: pointerup (end drag)
ResizableHandle->>page.tsx: onDragging(false)
page.tsx->>browserRuntimeRegistry: setResizePassthrough(false)
browserRuntimeRegistry->>browserRuntimeRegistry: passthroughReasons.delete("resize")
browserRuntimeRegistry->>Webview: pointerEvents = "auto"
Note over browserRuntimeRegistry,Webview: Safety net: window blur clears both drag and resize reasons
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts
Line: 108-115
Comment:
**`blur` capture fires for every element blur, not just window focus loss**
The listener is registered with `useCapture: true`, which means it fires for *any* element `blur` inside the document, not only when the browser window itself loses focus. If focus moves between DOM elements (e.g., a toolbar input loses focus while the user has started a resize drag), this will call `setInteractionPassthrough("resize", false)` mid-drag and restore `pointerEvents: "auto"` on visible webviews — allowing the webview to steal the pointer and break the ongoing resize gesture.
The intended behavior (clear passthrough when the user leaves the app entirely) is better expressed with either `useCapture: false` (window's own blur) or `window.addEventListener("visibilitychange", ...)`. All other listeners in `installGlobalListeners` use capture to catch events from child elements, which is correct for `dragstart`/`dragend`/`drop`, but for `blur` the semantics are inverted.
```suggestion
window.addEventListener(
"blur",
() => {
this.setInteractionPassthrough("drag", false);
this.setInteractionPassthrough("resize", false);
},
);
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "Handle browser passthrough during v2 res..." | Re-trigger Greptile
| window.addEventListener( | ||
| "blur", | ||
| () => { | ||
| this.setInteractionPassthrough("drag", false); | ||
| this.setInteractionPassthrough("resize", false); | ||
| }, | ||
| true, | ||
| ); |
There was a problem hiding this comment.
blur capture fires for every element blur, not just window focus loss
The listener is registered with useCapture: true, which means it fires for any element blur inside the document, not only when the browser window itself loses focus. If focus moves between DOM elements (e.g., a toolbar input loses focus while the user has started a resize drag), this will call setInteractionPassthrough("resize", false) mid-drag and restore pointerEvents: "auto" on visible webviews — allowing the webview to steal the pointer and break the ongoing resize gesture.
The intended behavior (clear passthrough when the user leaves the app entirely) is better expressed with either useCapture: false (window's own blur) or window.addEventListener("visibilitychange", ...). All other listeners in installGlobalListeners use capture to catch events from child elements, which is correct for dragstart/dragend/drop, but for blur the semantics are inverted.
| window.addEventListener( | |
| "blur", | |
| () => { | |
| this.setInteractionPassthrough("drag", false); | |
| this.setInteractionPassthrough("resize", false); | |
| }, | |
| true, | |
| ); | |
| window.addEventListener( | |
| "blur", | |
| () => { | |
| this.setInteractionPassthrough("drag", false); | |
| this.setInteractionPassthrough("resize", false); | |
| }, | |
| ); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts
Line: 108-115
Comment:
**`blur` capture fires for every element blur, not just window focus loss**
The listener is registered with `useCapture: true`, which means it fires for *any* element `blur` inside the document, not only when the browser window itself loses focus. If focus moves between DOM elements (e.g., a toolbar input loses focus while the user has started a resize drag), this will call `setInteractionPassthrough("resize", false)` mid-drag and restore `pointerEvents: "auto"` on visible webviews — allowing the webview to steal the pointer and break the ongoing resize gesture.
The intended behavior (clear passthrough when the user leaves the app entirely) is better expressed with either `useCapture: false` (window's own blur) or `window.addEventListener("visibilitychange", ...)`. All other listeners in `installGlobalListeners` use capture to catch events from child elements, which is correct for `dragstart`/`dragend`/`drop`, but for `blur` the semantics are inverted.
```suggestion
window.addEventListener(
"blur",
() => {
this.setInteractionPassthrough("drag", false);
this.setInteractionPassthrough("resize", false);
},
);
```
How can I resolve this? If you propose a fix, please make it concise.
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsx (1)
454-461: Wiring looks correct; minor optional simplification.The unmount cleanup is a nice safety net for users who close the workspace mid-resize. Since
browserRuntimeRegistryis a module-level singleton,setBrowserResizePassthroughdoesn't strictly needuseCallback— you could passbrowserRuntimeRegistry.setResizePassthrough.bind(browserRuntimeRegistry)once or just inline a one-liner. Not a blocker; current form reads fine.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/page.tsx around lines 454 - 461, The useCallback wrapper around setBrowserResizePassthrough is unnecessary because browserRuntimeRegistry is a module-level singleton; replace the useCallback-defined setBrowserResizePassthrough with a direct reference or bound method (e.g., pass browserRuntimeRegistry.setResizePassthrough.bind(browserRuntimeRegistry) or inline a one-liner) and keep the existing useEffect cleanup that calls browserRuntimeRegistry.setResizePassthrough(false); update any references to the former setBrowserResizePassthrough accordingly so there are no dangling usages.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/page.tsx:
- Around line 454-461: The useCallback wrapper around
setBrowserResizePassthrough is unnecessary because browserRuntimeRegistry is a
module-level singleton; replace the useCallback-defined
setBrowserResizePassthrough with a direct reference or bound method (e.g., pass
browserRuntimeRegistry.setResizePassthrough.bind(browserRuntimeRegistry) or
inline a one-liner) and keep the existing useEffect cleanup that calls
browserRuntimeRegistry.setResizePassthrough(false); update any references to the
former setBrowserResizePassthrough accordingly so there are no dangling usages.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 63299b26-d916-49fd-81c8-1d14eccdc700
📒 Files selected for processing (5)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsxpackages/panes/src/react/components/Workspace/Workspace.tsxpackages/panes/src/react/components/Workspace/components/Tab/Tab.tsxpackages/panes/src/react/types.ts
There was a problem hiding this comment.
1 issue found across 5 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts">
<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts:96">
P1: `blur` with `useCapture: true` fires during the capture phase for *every* element that loses focus in the document, not only when the window itself loses focus. During a resize drag, any incidental focus change (e.g., a toolbar input blur) will clear the resize passthrough and restore `pointerEvents: 'auto'` on webviews, breaking the gesture. Remove the capture flag so the listener only fires for the window's own blur event.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
81c1059 to
dd07890
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/panes/src/react/components/Workspace/components/Tab/Tab.tsx`:
- Around line 96-100: The Tab component needs an unmount cleanup to clear an
active resize claim: add a useEffect in the component that, on unmount, checks
if a drag was active and calls onResizeDragging?.(false, resizeSourceId) to
release the claim; reference the existing onResizeDragging prop, resizeSourceId
identifier, and the ResizableHandle usage to locate where the resize state is
managed and invoke the cleanup so an active drag cannot remain stuck when the
Tab/SplitView unmounts.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3412029f-173d-4f83-9f47-681924f9e9a7
📒 Files selected for processing (5)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsxpackages/panes/src/react/components/Workspace/Workspace.tsxpackages/panes/src/react/components/Workspace/components/Tab/Tab.tsxpackages/panes/src/react/types.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/panes/src/react/components/Workspace/Workspace.tsx
- packages/panes/src/react/types.ts
- apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsx
- apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts
66c10a0 to
3c5f302
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts (1)
93-127: Optional: collapse the pass-through wrapper arrow functions.Most listeners take
eventand forward it; the static arrows can be replaced with the bound method to slightly cut noise. Purely cosmetic — feel free to skip.♻️ Optional refactor
- window.addEventListener( - "dragstart", - () => this.setPointerPassthroughClaim("drag:window", true), - true, - ); - window.addEventListener( - "dragend", - () => this.setPointerPassthroughClaim("drag:window", false), - true, - ); - window.addEventListener( - "drop", - () => this.setPointerPassthroughClaim("drag:window", false), - true, - ); - window.addEventListener( - "pointerdown", - (event) => this.handleResizePointerDown(event), - true, - ); - window.addEventListener( - "pointerup", - (event) => this.clearResizePointer(event), - true, - ); - window.addEventListener( - "pointercancel", - (event) => this.clearResizePointer(event), - true, - ); - window.addEventListener( - "lostpointercapture", - (event) => this.clearResizePointer(event), - true, - ); + const setDrag = (active: boolean) => () => + this.setPointerPassthroughClaim("drag:window", active); + const onResizeDown = this.handleResizePointerDown.bind(this); + const onResizeUp = this.clearResizePointer.bind(this); + window.addEventListener("dragstart", setDrag(true), true); + window.addEventListener("dragend", setDrag(false), true); + window.addEventListener("drop", setDrag(false), true); + window.addEventListener("pointerdown", onResizeDown, true); + window.addEventListener("pointerup", onResizeUp, true); + window.addEventListener("pointercancel", onResizeUp, true); + window.addEventListener("lostpointercapture", onResizeUp, true);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts around lines 93 - 127, The event listener callbacks can be simplified by passing bound methods instead of inline arrow wrappers: replace the arrow for "pointerdown" with this.handleResizePointerDown.bind(this), and for "pointerup", "pointercancel", and "lostpointercapture" replace their arrows with this.clearResizePointer.bind(this); for "dragstart", "dragend", and "drop" where setPointerPassthroughClaim is called with fixed args, use this.setPointerPassthroughClaim.bind(this, "drag:window", true) and this.setPointerPassthroughClaim.bind(this, "drag:window", false) respectively; keep the third argument (capture = true) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts:
- Around line 128-132: The window "blur" listener is registered with
capture=true which causes it to run for descendant element blur events and
clears resize pointer state; change the listener in browserRuntimeRegistry where
window.addEventListener("blur", () => this.clearPointerPassthroughClaims(),
true) is added so it does not use capture (remove the third argument or pass
false) so the handler only runs when the window itself blurs (use the existing
clearPointerPassthroughClaims/clearPointerPassthrough methods as-is).
---
Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts:
- Around line 93-127: The event listener callbacks can be simplified by passing
bound methods instead of inline arrow wrappers: replace the arrow for
"pointerdown" with this.handleResizePointerDown.bind(this), and for "pointerup",
"pointercancel", and "lostpointercapture" replace their arrows with
this.clearResizePointer.bind(this); for "dragstart", "dragend", and "drop" where
setPointerPassthroughClaim is called with fixed args, use
this.setPointerPassthroughClaim.bind(this, "drag:window", true) and
this.setPointerPassthroughClaim.bind(this, "drag:window", false) respectively;
keep the third argument (capture = true) unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 628176f6-9037-4807-9448-eb113c9751a5
📒 Files selected for processing (1)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts
There was a problem hiding this comment.
♻️ Duplicate comments (1)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts (1)
129-129:⚠️ Potential issue | 🔴 Critical
blurlistener withuseCapture=truestill clears resize state on every descendant blur.The capture-phase
blurlistener onwindowruns whenever any descendant element loses focus (capture phase descends from root to target, even thoughblurdoesn't bubble). Mid-resize focus shifts (e.g., the resize handle taking focus, an input losing focus when the user clicks the handle) will invokeclearPointerPassthrough()and drop the activeresizePointerIds, restoringpointer-events: autoon the webview while the user is still dragging. The intent is clearly to react only to the window losing focus, so the capture flag should be removed.🛡️ Suggested fix
- window.addEventListener("blur", () => this.clearPointerPassthrough(), true); + window.addEventListener("blur", () => this.clearPointerPassthrough());🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts at line 129, The blur listener is currently registered in the capture phase which causes clearPointerPassthrough() to run on descendant focus losses; change the registration so it only fires for the window losing focus by removing the capture flag (i.e., call window.addEventListener("blur", () => this.clearPointerPassthrough()) or set the third argument to false) for the listener declared with window.addEventListener in browserRuntimeRegistry.ts; this ensures clearPointerPassthrough() and any state like resizePointerIds are only cleared when the window itself blurs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts:
- Line 129: The blur listener is currently registered in the capture phase which
causes clearPointerPassthrough() to run on descendant focus losses; change the
registration so it only fires for the window losing focus by removing the
capture flag (i.e., call window.addEventListener("blur", () =>
this.clearPointerPassthrough()) or set the third argument to false) for the
listener declared with window.addEventListener in browserRuntimeRegistry.ts;
this ensures clearPointerPassthrough() and any state like resizePointerIds are
only cleared when the window itself blurs.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8c61a7fa-3a89-4e07-b8b3-1afffdc1e70a
📒 Files selected for processing (1)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts
3c5f302 to
f1150d4
Compare
d253f7d to
7cc016d
Compare
7cc016d to
f190bbe
Compare
f190bbe to
c3a04a3
Compare
3 PR (#442, #443, #444) で取り込み済みの 9 commits を git 履歴上もマージ済みに記録する。 内容差分は無し (merge -s ours)。 取り込み内容: - 6b96acd Improve sidebar group management UX (superset-sh#3745) - a4079e7 Update dashboard sidebar workspace icons (superset-sh#3755) - d3753d0 [codex] Use dynamic footer copyright years (superset-sh#3754) - ce606be Handle browser passthrough during v2 resize (superset-sh#3744) - b1e1eb7 Refactor v2 workspace page (superset-sh#3747) - 8693869 [codex] move v2 toggle to experimental settings (superset-sh#3748) - ef3f381 Revert "fix(desktop): refit v2 terminal after font settle (superset-sh#3742)" (superset-sh#3750) - 手動移植 (vibrancy patch 維持) - 25b2d52 Show terminal sessions from all workspaces in dropdown (superset-sh#3751) - 62737db fix v1 terminal resize repaint (superset-sh#3756)
Summary
WorkspaceInteractionStatecallback from@superset/paneswithresizeActiveso consumers can react to pane-level resize interactions without browser-specific APIs.Workspace, including cleanup on handle unmount and window blur, so overlapping resize activity does not clear passthrough too early.Why
V1 let resize gestures keep control when the cursor crossed browser content. V2 browser panes use persistent fixed-position webviews, so the runtime needs to temporarily disable webview pointer handling during shell-owned interactions.
This keeps the ownership boundaries cleaner than a browser-runtime DOM selector listener: panes expose generic interaction state, the desktop page aggregates page-level shell state, and the browser runtime only knows whether shell passthrough is active. Window drag passthrough remains tracked separately.
Validation
bun --filter @superset/panes typecheckbun --filter @superset/desktop typecheckbun --filter @superset/panes testbunx @biomejs/biome@2.4.2 check apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/\$workspaceId/page.tsx apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/\$workspaceId/hooks/usePaneRegistry/components/BrowserPane/browserRuntimeRegistry.ts packages/panes/src/index.ts packages/panes/src/react/index.ts packages/panes/src/react/types.ts packages/panes/src/react/components/Workspace/Workspace.tsx packages/panes/src/react/components/Workspace/components/Tab/Tab.tsxSummary by CodeRabbit
Refactor
New Features