Defer protected app data reads until user action (#1370)

This commit is contained in:
Neil
2026-05-02 18:15:52 -07:00
committed by GitHub
parent b309f49ee3
commit ae0fc9c49a
7 changed files with 52 additions and 26 deletions
-2
View File
@@ -96,7 +96,6 @@ function App(): React.JSX.Element {
hydrateEditorSession: s.hydrateEditorSession,
hydrateBrowserSession: s.hydrateBrowserSession,
fetchBrowserSessionProfiles: s.fetchBrowserSessionProfiles,
fetchDetectedBrowsers: s.fetchDetectedBrowsers,
reconnectPersistedTerminals: s.reconnectPersistedTerminals,
setDeferredSshReconnectTargets: s.setDeferredSshReconnectTargets,
setSshConnectionState: s.setSshConnectionState,
@@ -233,7 +232,6 @@ function App(): React.JSX.Element {
actions.hydrateEditorSession(session)
actions.hydrateBrowserSession(session)
await actions.fetchBrowserSessionProfiles()
await actions.fetchDetectedBrowsers()
// Why: SSH connections must be re-established BEFORE terminal
// reconnect so that reconnectPersistedTerminals can route SSH-backed
@@ -42,6 +42,7 @@ export function BrowserToolbarMenu({
const createBrowserSessionProfile = useAppStore((s) => s.createBrowserSessionProfile)
const importCookiesFromBrowser = useAppStore((s) => s.importCookiesFromBrowser)
const importCookiesToProfile = useAppStore((s) => s.importCookiesToProfile)
const fetchDetectedBrowsers = useAppStore((s) => s.fetchDetectedBrowsers)
const browserSessionImportState = useAppStore((s) => s.browserSessionImportState)
const [newProfileDialogOpen, setNewProfileDialogOpen] = useState(false)
@@ -171,7 +172,15 @@ export function BrowserToolbarMenu({
<DropdownMenuSeparator />
<DropdownMenuSub>
<DropdownMenuSub
onOpenChange={(open) => {
if (open) {
// Why: macOS treats other browsers' profile folders as app
// data. Only probe them when the user opens the import menu.
void fetchDetectedBrowsers()
}
}}
>
<DropdownMenuSubTrigger disabled={browserSessionImportState?.status === 'importing'}>
<Import className="mr-2 size-3.5" />
Import Cookies
@@ -46,6 +46,7 @@ export function BrowserProfileRow({
isDefault
}: BrowserProfileRowProps): React.JSX.Element {
const isImporting = importState?.profileId === profile.id && importState.status === 'importing'
const fetchDetectedBrowsers = useAppStore((s) => s.fetchDetectedBrowsers)
const handleImportFromBrowser = async (
browserFamily: string,
@@ -115,7 +116,15 @@ export function BrowserProfileRow({
)}
</div>
<div className="flex shrink-0 items-center gap-1" onClick={(e) => e.stopPropagation()}>
<DropdownMenu>
<DropdownMenu
onOpenChange={(open) => {
if (open) {
// Why: macOS treats other browsers' profile folders as app
// data. Only probe them when the user opens the import menu.
void fetchDetectedBrowsers()
}
}}
>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
@@ -77,8 +77,7 @@ export function BrowserUseSetup({
}
void refreshCli()
void fetchBrowserSessionProfiles()
void fetchDetectedBrowsers()
}, [browserUseEnabled, fetchBrowserSessionProfiles, fetchDetectedBrowsers])
}, [browserUseEnabled, fetchBrowserSessionProfiles])
const defaultProfile = browserSessionProfiles.find((p) => p.id === 'default')
// Why: this step explicitly imports into the default profile, so completion
@@ -325,7 +324,15 @@ export function BrowserUseSetup({
</button>
) : null}
</div>
<DropdownMenu>
<DropdownMenu
onOpenChange={(open) => {
if (open) {
// Why: macOS treats other browsers' profile folders as app
// data. Only probe them when the user opens the import menu.
void fetchDetectedBrowsers()
}
}}
>
<DropdownMenuTrigger asChild>
<Button
variant={cookiesImported ? 'outline' : 'default'}
+7 -1
View File
@@ -104,6 +104,7 @@ export type BrowserSlice = {
profiles: { name: string; directory: string }[]
selectedProfile: string
}[]
detectedBrowsersLoaded: boolean
fetchDetectedBrowsers: () => Promise<void>
importCookiesFromBrowser: (
profileId: string,
@@ -1283,8 +1284,12 @@ export const createBrowserSlice: StateCreator<AppState, [], [], BrowserSlice> =
},
detectedBrowsers: [],
detectedBrowsersLoaded: false,
fetchDetectedBrowsers: async () => {
if (get().detectedBrowsersLoaded) {
return
}
try {
const browsers = (await window.api.browser.sessionDetectBrowsers()) as {
family: string
@@ -1292,9 +1297,10 @@ export const createBrowserSlice: StateCreator<AppState, [], [], BrowserSlice> =
profiles: { name: string; directory: string }[]
selectedProfile: string
}[]
set({ detectedBrowsers: browsers })
set({ detectedBrowsers: browsers, detectedBrowsersLoaded: true })
} catch {
/* best-effort — empty list is acceptable fallback */
set({ detectedBrowsersLoaded: true })
}
},