fix: prevent duplicate vault folder pickers
This commit is contained in:
@@ -85,6 +85,25 @@ describe('pickFolder', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('ignores overlapping native folder picker requests while one is open', async () => {
|
||||
vi.mocked(isTauri).mockReturnValue(true)
|
||||
vi.mocked(isRestartRequiredAfterUpdate).mockReturnValue(false)
|
||||
|
||||
let resolveOpen: ((path: string) => void) | null = null
|
||||
openMock.mockReturnValueOnce(new Promise((resolve) => {
|
||||
resolveOpen = resolve
|
||||
}))
|
||||
|
||||
const firstRequest = pickFolder('Open vault folder')
|
||||
const secondRequest = pickFolder('Open vault folder')
|
||||
|
||||
await expect(secondRequest).resolves.toBeNull()
|
||||
expect(openMock).toHaveBeenCalledTimes(1)
|
||||
|
||||
resolveOpen?.('/Users/test/restored-vault')
|
||||
await expect(firstRequest).resolves.toBe('/Users/test/restored-vault')
|
||||
})
|
||||
|
||||
it('normalizes native file URLs to filesystem paths', async () => {
|
||||
vi.mocked(isTauri).mockReturnValue(true)
|
||||
vi.mocked(isRestartRequiredAfterUpdate).mockReturnValue(false)
|
||||
|
||||
@@ -75,24 +75,32 @@ function normalizePickedFolderPath(selected: string | string[] | null): string |
|
||||
}
|
||||
}
|
||||
|
||||
let folderPickerRequestInFlight = false
|
||||
|
||||
/**
|
||||
* Opens a native folder picker dialog (Tauri) or falls back to prompt (browser).
|
||||
* Returns the selected folder path, or null if the user cancelled.
|
||||
*/
|
||||
export async function pickFolder(title?: string): Promise<string | null> {
|
||||
if (isTauri()) {
|
||||
if (isRestartRequiredAfterUpdate()) {
|
||||
throw new NativeFolderPickerBlockedError()
|
||||
}
|
||||
if (folderPickerRequestInFlight) return null
|
||||
|
||||
const { open } = await import('@tauri-apps/plugin-dialog')
|
||||
const selected = await open({
|
||||
directory: true,
|
||||
multiple: false,
|
||||
title: title ?? 'Select folder',
|
||||
})
|
||||
return normalizePickedFolderPath(selected)
|
||||
folderPickerRequestInFlight = true
|
||||
try {
|
||||
if (isTauri()) {
|
||||
if (isRestartRequiredAfterUpdate()) {
|
||||
throw new NativeFolderPickerBlockedError()
|
||||
}
|
||||
|
||||
const { open } = await import('@tauri-apps/plugin-dialog')
|
||||
const selected = await open({
|
||||
directory: true,
|
||||
multiple: false,
|
||||
title: title ?? 'Select folder',
|
||||
})
|
||||
return normalizePickedFolderPath(selected)
|
||||
}
|
||||
return normalizePickedFolderPath(prompt(title ?? 'Enter folder path:'))
|
||||
} finally {
|
||||
folderPickerRequestInFlight = false
|
||||
}
|
||||
// Browser fallback: prompt for path
|
||||
return normalizePickedFolderPath(prompt(title ?? 'Enter folder path:'))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user