diff --git a/src/App.tsx b/src/App.tsx index 5cd0752c..c2437473 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -86,7 +86,7 @@ import { initializeNoteProperties } from './utils/initializeNoteProperties' import { filterEntries, filterInboxEntries, type NoteListFilter } from './utils/noteListHelpers' import { openNoteInNewWindow } from './utils/openNoteWindow' import { isWindows } from './utils/platform' -import { refreshPulledVaultState } from './utils/pulledVaultRefresh' +import { getPulledVaultUpdateOptions, refreshPulledVaultState } from './utils/pulledVaultRefresh' import { isNoteWindow, getNoteWindowParams } from './utils/windowMode' import { GitSetupDialog } from './components/GitRequiredModal' import { RenameDetectedBanner } from './components/RenameDetectedBanner' @@ -652,7 +652,7 @@ function App() { vault.unsavedPaths, ]) const handlePulledVaultUpdate = useCallback( - (updatedFiles: string[]) => handleVaultUpdate(updatedFiles), + (updatedFiles: string[]) => handleVaultUpdate(updatedFiles, getPulledVaultUpdateOptions()), [handleVaultUpdate], ) const handleFocusedVaultUpdate = useCallback( diff --git a/src/utils/pulledVaultRefresh.test.ts b/src/utils/pulledVaultRefresh.test.ts index 66b5987f..38290244 100644 --- a/src/utils/pulledVaultRefresh.test.ts +++ b/src/utils/pulledVaultRefresh.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from 'vitest' import type { VaultEntry } from '../types' -import { refreshPulledVaultState } from './pulledVaultRefresh' +import { getPulledVaultUpdateOptions, refreshPulledVaultState } from './pulledVaultRefresh' function makeEntry(path: string, title = 'Test note'): VaultEntry { return { @@ -30,6 +30,10 @@ function makeOptions(overrides: Partial { + it('marks pull-originated vault updates as focused-editor preserving', () => { + expect(getPulledVaultUpdateOptions()).toEqual({ preserveFocusedEditor: true }) + }) + it('reloads vault-derived data and refreshes the active note when pull updated it', async () => { const options = makeOptions() diff --git a/src/utils/pulledVaultRefresh.ts b/src/utils/pulledVaultRefresh.ts index 9b4053bb..89bbdb1c 100644 --- a/src/utils/pulledVaultRefresh.ts +++ b/src/utils/pulledVaultRefresh.ts @@ -15,6 +15,13 @@ interface PulledVaultRefreshOptions { vaultPath: string } +interface ActiveTabRefreshGuardOptions { + activeTabPath: string + latestActiveTabPath: string + hasUnsavedChanges: (path: string) => boolean + shouldKeepActiveEditorMounted?: () => boolean +} + function resolveUpdatedFilePath(path: string, vaultPath: string): string { if (path.startsWith('/')) return normalizeNotePathForIdentity(path) return normalizeNotePathForIdentity(joinVaultPath(vaultPath, path)) @@ -28,6 +35,21 @@ function didActivePathChange(initialPath: string, latestPath: string): boolean { return !notePathsMatch(initialPath, latestPath) } +function shouldKeepCurrentActiveTabMounted({ + activeTabPath, + latestActiveTabPath, + hasUnsavedChanges, + shouldKeepActiveEditorMounted, +}: ActiveTabRefreshGuardOptions): boolean { + if (didActivePathChange(activeTabPath, latestActiveTabPath)) return true + if (hasUnsavedChanges(latestActiveTabPath)) return true + return shouldKeepActiveEditorMounted?.() === true +} + +export function getPulledVaultUpdateOptions(): { preserveFocusedEditor: true } { + return { preserveFocusedEditor: true } +} + export async function refreshPulledVaultState(options: PulledVaultRefreshOptions): Promise { const { activeTabPath, @@ -51,9 +73,12 @@ export async function refreshPulledVaultState(options: PulledVaultRefreshOptions const latestActiveTabPath = getActiveTabPath?.() ?? activeTabPath if (!activeTabPath || !latestActiveTabPath) return entries - if (didActivePathChange(activeTabPath, latestActiveTabPath)) return entries - if (hasUnsavedChanges(latestActiveTabPath)) return entries - if (shouldKeepActiveEditorMounted?.()) return entries + if (shouldKeepCurrentActiveTabMounted({ + activeTabPath, + latestActiveTabPath, + hasUnsavedChanges, + shouldKeepActiveEditorMounted, + })) return entries const refreshedEntry = findByNotePath(entries, latestActiveTabPath) if (!refreshedEntry) {