diff --git a/src/hooks/useVaultLoader.extra.test.ts b/src/hooks/useVaultLoader.extra.test.ts index 610059ba..c12e9f98 100644 --- a/src/hooks/useVaultLoader.extra.test.ts +++ b/src/hooks/useVaultLoader.extra.test.ts @@ -2,6 +2,7 @@ import { act, renderHook, waitFor } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import { useVaultLoader } from './useVaultLoader' import type { ModifiedFile, VaultEntry, ViewFile } from '../types' +import { loadedWorkspacePathsFromEntries } from './vaultWorkspaceEntries' const clearPrefetchCache = vi.fn() const backendInvokeFn = vi.fn() @@ -296,4 +297,30 @@ describe('useVaultLoader extra', () => { expect(folders).toEqual([]) expect(views).toEqual([]) }) + + it('does not infer the fallback workspace from untagged entries when explicit workspace metadata is required', () => { + expect(loadedWorkspacePathsFromEntries([ + makeEntry({ path: '/research/research-beacon.md' }), + ], '/field', { inferFallbackWorkspacePath: false })).toEqual([]) + }) + + it('uses explicit workspace metadata when fallback inference is disabled', () => { + expect(loadedWorkspacePathsFromEntries([ + makeEntry({ + path: '/research/research-beacon.md', + workspace: { + id: 'workspace', + label: 'Workspace', + alias: 'workspace', + path: '/research', + shortLabel: 'WS', + color: null, + icon: null, + mounted: true, + available: true, + defaultForNewNotes: false, + }, + }), + ], '/field', { inferFallbackWorkspacePath: false })).toEqual(['/research']) + }) }) diff --git a/src/hooks/useVaultLoader.ts b/src/hooks/useVaultLoader.ts index 36627278..46479691 100644 --- a/src/hooks/useVaultLoader.ts +++ b/src/hooks/useVaultLoader.ts @@ -378,6 +378,10 @@ function useInitialVaultLoad(options: InitialVaultLoadOptions) { defaultWorkspacePath, } = options const loadOptionsRef = useInitialVaultLoadSnapshot(vaults, defaultWorkspacePath) + const loadOptionsKey = useMemo( + () => workspacePathSetKey(uniqueWorkspacePathsFromVaults(vaultPath, vaults)), + [vaultPath, vaults], + ) useEffect(() => { const path = vaultPath @@ -415,6 +419,7 @@ function useInitialVaultLoad(options: InitialVaultLoadOptions) { resetReloading, setEntries, setFolders, setIsLoading, setModifiedFiles, setModifiedFilesError, setViews, loadOptionsRef, + loadOptionsKey, ]) } @@ -836,21 +841,25 @@ function useInitialLoadedWorkspaceMarker({ isLoading, loadedWorkspacePathsRef, vaultPath, + vaults, }: { entries: VaultEntry[] initialLoadedVaultPathRef: MutableRefObject isLoading: boolean loadedWorkspacePathsRef: MutableRefObject> vaultPath: string + vaults?: VaultOption[] }) { useEffect(() => { if (isLoading || !hasVaultPath({ vaultPath }) || initialLoadedVaultPathRef.current === vaultPath) return initialLoadedVaultPathRef.current = vaultPath loadedWorkspacePathsRef.current = new Set([ ...loadedWorkspacePathsRef.current, - ...loadedWorkspacePathsFromEntries(entries, vaultPath), + ...loadedWorkspacePathsFromEntries(entries, vaultPath, { + inferFallbackWorkspacePath: !vaults?.length, + }), ]) - }, [entries, initialLoadedVaultPathRef, isLoading, loadedWorkspacePathsRef, vaultPath]) + }, [entries, initialLoadedVaultPathRef, isLoading, loadedWorkspacePathsRef, vaultPath, vaults]) } function useWorkspaceMetadataRetagEffect({ @@ -1022,7 +1031,7 @@ function useWorkspaceEntrySync({ const refs = useWorkspaceLoadRefs() usePrunedWorkspaceLoadRefs(refs, desiredWorkspaceKey, desiredWorkspacePaths) - useInitialLoadedWorkspaceMarker({ entries, vaultPath, isLoading, ...refs }) + useInitialLoadedWorkspaceMarker({ entries, vaultPath, vaults, isLoading, ...refs }) useWorkspaceMetadataRetagEffect({ defaultWorkspacePath, desiredWorkspaceKey, diff --git a/src/hooks/vaultWorkspaceEntries.ts b/src/hooks/vaultWorkspaceEntries.ts index b30bacee..fba484af 100644 --- a/src/hooks/vaultWorkspaceEntries.ts +++ b/src/hooks/vaultWorkspaceEntries.ts @@ -23,19 +23,30 @@ export function initialVaultsForPath(path: string, vaults?: VaultOption[]): Vaul return matchingVaults.length > 0 ? matchingVaults : undefined } -function workspacePathsFromEntries(entries: VaultEntry[], fallbackVaultPath: string): string[] { +function workspacePathsFromEntries( + entries: VaultEntry[], + fallbackVaultPath: string, + inferFallbackWorkspacePath: boolean, +): string[] { const paths = new Set() for (const entry of entries) { - const path = entryWorkspacePath(entry, fallbackVaultPath) + const path = inferFallbackWorkspacePath + ? entryWorkspacePath(entry, fallbackVaultPath) + : entry.workspace?.path ?? '' if (path.trim()) paths.add(path) } return [...paths] } -export function loadedWorkspacePathsFromEntries(entries: VaultEntry[], fallbackVaultPath: string): string[] { - const paths = workspacePathsFromEntries(entries, fallbackVaultPath) +export function loadedWorkspacePathsFromEntries( + entries: VaultEntry[], + fallbackVaultPath: string, + options: { inferFallbackWorkspacePath?: boolean } = {}, +): string[] { + const inferFallbackWorkspacePath = options.inferFallbackWorkspacePath ?? true + const paths = workspacePathsFromEntries(entries, fallbackVaultPath, inferFallbackWorkspacePath) if (paths.length > 0) return paths - return fallbackVaultPath.trim() ? [fallbackVaultPath] : [] + return inferFallbackWorkspacePath && fallbackVaultPath.trim() ? [fallbackVaultPath] : [] } type WorkspaceIdentityMetadataKey =