Skip to content

Commit 9d22526

Browse files
committed
fix(desktop-browser): keep error-page focus recovery inside the browser and route hard reload through recovery
1 parent 69326d2 commit 9d22526

4 files changed

Lines changed: 39 additions & 22 deletions

File tree

‎apps/desktop/src/main/browser-agent/session.ts‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2012,6 +2012,20 @@ export function reloadPage(contents: WebContents): void {
20122012
contents.reload()
20132013
}
20142014

2015+
/**
2016+
* Reloads past the HTTP cache, the browser's Shift-reload. A page showing an
2017+
* issue takes the same recovery as a plain reload instead: a hung renderer
2018+
* must be restarted, since reloading it in place waits on the hung page.
2019+
*/
2020+
function hardReloadPage(contents: WebContents): void {
2021+
if (tabForContents(contents)?.pageIssue) {
2022+
reloadPage(contents)
2023+
return
2024+
}
2025+
prepareExplicitNavigation(contents)
2026+
contents.reloadIgnoringCache()
2027+
}
2028+
20152029
/** Hands one page selection to the exact app window and chat hosting its tab. */
20162030
function addPageSelectionToChat(contents: WebContents, text: string): void {
20172031
if (!text.trim() || getBrowserScopeId() !== getActiveBrowserScopeId()) return
@@ -2494,8 +2508,7 @@ function initializeTabView(
24942508
return
24952509
}
24962510
if (shortcut === 'hard-reload') {
2497-
prepareExplicitNavigation(contents)
2498-
contents.reloadIgnoringCache()
2511+
hardReloadPage(contents)
24992512
return
25002513
}
25012514

@@ -3512,8 +3525,7 @@ export function handleFocusedShortcut(
35123525
reloadPage(shortcutTab.view.webContents)
35133526
return true
35143527
case 'hard-reload':
3515-
prepareExplicitNavigation(shortcutTab.view.webContents)
3516-
shortcutTab.view.webContents.reloadIgnoringCache()
3528+
hardReloadPage(shortcutTab.view.webContents)
35173529
return true
35183530
case 'back':
35193531
goBack(shortcutTab.view.webContents)

‎apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-find-bar.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export function BrowserFindBar({ inputRef, onClose, scopeId }: BrowserFindBarPro
142142
// The panel and the global command layer both listen for these.
143143
event.stopPropagation()
144144
// Keys during an IME composition edit the composed text.
145-
if (event.nativeEvent.isComposing) return
145+
if (event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) return
146146
if (event.key === 'Escape') {
147147
event.preventDefault()
148148
dismiss()

‎apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-page-issue.tsx‎

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef } from 'react'
1+
import { type RefObject, useEffect, useRef } from 'react'
22
import type { BrowserPageIssue } from '@sim/browser-protocol'
33
import { Chip } from '@sim/emcn'
44
import { CircleAlert, Globe, RefreshCw } from '@sim/emcn/icons'
@@ -7,6 +7,8 @@ interface BrowserPageIssueProps {
77
issue: BrowserPageIssue
88
onReload: () => void
99
focusRecovery: boolean
10+
/** The browser panel; focus anywhere else in Sim is never taken for recovery. */
11+
panelRef: RefObject<HTMLElement | null>
1012
}
1113

1214
interface BrowserPageIssueCopy {
@@ -125,29 +127,31 @@ export function browserPageIssueCopy(issue: BrowserPageIssue): BrowserPageIssueC
125127
}
126128
}
127129

128-
function isEditingOutside(heading: HTMLElement | null): boolean {
130+
/**
131+
* Whether the user's focus is somewhere in Sim other than the browser.
132+
* `document.activeElement` survives a window blur, so a caret left in chat
133+
* still counts as elsewhere.
134+
*/
135+
function isFocusElsewhere(panel: HTMLElement | null): boolean {
129136
const active = document.activeElement
130-
// activeElement survives a window blur, so a caret left in chat still counts.
131-
if (!(active instanceof HTMLElement)) return false
132-
const section = heading?.closest('section')
133-
if (section?.contains(active)) return false
134-
return (
135-
active.isContentEditable ||
136-
active instanceof HTMLInputElement ||
137-
active instanceof HTMLTextAreaElement
138-
)
137+
if (!(active instanceof HTMLElement) || active === document.body) return false
138+
return !panel?.contains(active)
139139
}
140140

141141
/** Replaces a hidden native page and optionally claims renderer focus for keyboard recovery. */
142-
export function BrowserPageIssueView({ issue, onReload, focusRecovery }: BrowserPageIssueProps) {
142+
export function BrowserPageIssueView({
143+
issue,
144+
onReload,
145+
focusRecovery,
146+
panelRef,
147+
}: BrowserPageIssueProps) {
143148
const headingRef = useRef<HTMLHeadingElement>(null)
144149
const copy = browserPageIssueCopy(issue)
145150

146151
useEffect(() => {
147-
// Keyboard recovery for someone who was in the page; a caret in chat or
148-
// any other Sim field stays where it is.
149-
if (focusRecovery && !isEditingOutside(headingRef.current)) headingRef.current?.focus()
150-
}, [focusRecovery, issue])
152+
// Keyboard recovery for someone who was in the browser.
153+
if (focusRecovery && !isFocusElsewhere(panelRef.current)) headingRef.current?.focus()
154+
}, [focusRecovery, issue, panelRef])
151155

152156
const Icon = issue.kind === 'load-error' ? Globe : CircleAlert
153157

‎apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-session.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,7 @@ export function BrowserSession({
11571157
onKeyDown={(event) => {
11581158
event.stopPropagation()
11591159
// Keys during an IME composition edit the composed text, not the URL.
1160-
if (event.nativeEvent.isComposing) return
1160+
if (event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) return
11611161
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
11621162
// Never move a highlight through a list that is not on screen.
11631163
if (!suggestionsOpen) return
@@ -1359,6 +1359,7 @@ export function BrowserSession({
13591359
<BrowserPageIssueView
13601360
issue={pageState.issue}
13611361
focusRecovery={visible}
1362+
panelRef={panelRef}
13621363
onReload={() => sendBrowserPanelAction('reload', {}, scopeId)}
13631364
/>
13641365
)}

0 commit comments

Comments
 (0)