diff --git a/src/hooks/useVaultLoader.empty-cache.test.ts b/src/hooks/useVaultLoader.empty-cache.test.ts index c67d5d02..a10209e6 100644 --- a/src/hooks/useVaultLoader.empty-cache.test.ts +++ b/src/hooks/useVaultLoader.empty-cache.test.ts @@ -61,6 +61,39 @@ describe('useVaultLoader empty cache recovery', () => { mockIsTauri = true }) + it('keeps mounted workspace entries visible while a newly active empty workspace loads', async () => { + const laputa = { label: 'Laputa', path: '/laputa', alias: 'laputa', available: true, mounted: true } + const refactoring = { label: 'Refactoring', path: '/refactoring', alias: 'refactoring', available: true, mounted: true } + const commandResults = new Map([ + ['reload_vault:/laputa', [makeEntry('/laputa/note/hello.md', 'Laputa Hello')]], + ['reload_vault:/refactoring', []], + ['list_vault:/refactoring', []], + ['get_modified_files:', []], + ['list_vault_folders:', []], + ['list_views:', []], + ]) + + backendInvokeFn.mockImplementation((command: string, args?: Record) => { + return Promise.resolve(commandResults.get(commandKey(command, args)) ?? null) + }) + + const { result, rerender } = renderHook( + ({ activePath, vaults }) => useVaultLoader(activePath, vaults, activePath, vaults), + { initialProps: { activePath: '/laputa', vaults: [laputa] } }, + ) + + await waitFor(() => { + expect(result.current.entries.map((entry) => entry.title)).toEqual(['Laputa Hello']) + }) + + rerender({ activePath: '/refactoring', vaults: [laputa, refactoring] }) + + expect(result.current.entries.map((entry) => entry.title)).toContain('Laputa Hello') + await waitFor(() => { + expect(result.current.entries.map((entry) => entry.title)).toContain('Laputa Hello') + }) + }) + it('reloads a background workspace when its cached startup listing is empty in Tauri mode', async () => { const brian = { label: 'Brian', path: '/brian', alias: 'brian', available: true, mounted: true } const laputa = { label: 'Laputa', path: '/laputa', alias: 'laputa', available: true, mounted: true } diff --git a/src/hooks/useVaultLoader.ts b/src/hooks/useVaultLoader.ts index 62b926a5..b5d3aa89 100644 --- a/src/hooks/useVaultLoader.ts +++ b/src/hooks/useVaultLoader.ts @@ -307,18 +307,22 @@ function shouldReuseLoadedWorkspaceEntries( return !!loadOptions.vaults?.length && isWorkspacePathLoaded(path) } -function resetInitialVaultLoadState(options: InitialVaultLoadEffectOptions, reuseLoadedWorkspaceEntries: boolean) { +function shouldPreserveWorkspaceEntries(loadOptions: InitialVaultLoadSnapshot): boolean { + return !!loadOptions.vaults?.length +} + +function resetInitialVaultLoadState(options: InitialVaultLoadEffectOptions, preserveWorkspaceEntries: boolean) { clearPrefetchCache() options.setViews([]) resetVaultState({ clearNewPaths: options.clearNewPaths, clearUnsaved: options.clearUnsaved, - setEntries: reuseLoadedWorkspaceEntries ? () => {} : options.setEntries, + setEntries: preserveWorkspaceEntries ? () => {} : options.setEntries, setFolders: options.setFolders, setIsLoading: options.setIsLoading, setModifiedFiles: options.setModifiedFiles, setModifiedFilesError: options.setModifiedFilesError, - setViews: reuseLoadedWorkspaceEntries ? () => {} : options.setViews, + setViews: preserveWorkspaceEntries ? () => {} : options.setViews, }) options.resetReloading() } @@ -395,7 +399,8 @@ function useInitialVaultLoad(options: InitialVaultLoadOptions) { vaultPath, vaults: loadOptions.vaults, } const reuseLoadedWorkspaceEntries = shouldReuseLoadedWorkspaceEntries(path, loadOptions, isWorkspacePathLoaded) - resetInitialVaultLoadState(effectOptions, reuseLoadedWorkspaceEntries) + const preserveWorkspaceEntries = reuseLoadedWorkspaceEntries || shouldPreserveWorkspaceEntries(loadOptions) + resetInitialVaultLoadState(effectOptions, preserveWorkspaceEntries) if (!hasVaultPath({ vaultPath: path })) return