Merge branch 'main' into pr-728
This commit is contained in:
@@ -525,7 +525,7 @@ describe('App', () => {
|
||||
// Entries appear in both Sidebar and NoteList
|
||||
expect(screen.getAllByText('Test Project').length).toBeGreaterThan(0)
|
||||
expect(screen.getAllByText('Software Development').length).toBeGreaterThan(0)
|
||||
})
|
||||
}, { timeout: SLOW_APP_READY_TIMEOUT_MS })
|
||||
})
|
||||
|
||||
it('keeps the app shell usable while the vault note scan is pending', async () => {
|
||||
@@ -1301,7 +1301,7 @@ describe('App', () => {
|
||||
|
||||
render(<App />)
|
||||
|
||||
expect(await screen.findByTestId('status-missing-git')).toBeInTheDocument()
|
||||
expect(await screen.findByTestId('status-missing-git', {}, { timeout: SLOW_APP_READY_TIMEOUT_MS })).toBeInTheDocument()
|
||||
fireEvent.click(screen.getByTestId('status-missing-git'))
|
||||
expect(await screen.findByText('Enable Git for this vault?')).toBeInTheDocument()
|
||||
|
||||
|
||||
@@ -143,10 +143,14 @@ async function enableTauriMode() {
|
||||
)
|
||||
}
|
||||
|
||||
function buildMountedWorkspaceLoadMock() {
|
||||
function buildMountedWorkspaceLoadMock(options: {
|
||||
pendingEntriesByPath?: Record<string, Promise<VaultEntry[]>>
|
||||
} = {}) {
|
||||
return ((cmd: string, args?: Record<string, unknown>) => {
|
||||
if (isVaultLoadCommand(cmd)) {
|
||||
const path = args?.path
|
||||
const path = typeof args?.path === 'string' ? args.path : ''
|
||||
const pendingEntries = options.pendingEntriesByPath?.[path]
|
||||
if (pendingEntries) return pendingEntries
|
||||
return Promise.resolve([{
|
||||
...mockEntries[0],
|
||||
path: `${path}/note/hello.md`,
|
||||
@@ -229,7 +233,7 @@ describe('useVaultLoader', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('does not re-add the base vault as a folder root after it is unmounted', async () => {
|
||||
it('keeps the active vault folder root visible when it is absent from mounted folder vaults', async () => {
|
||||
const entryVaults = [
|
||||
{ label: 'Brian', path: '/brian', alias: 'brian', available: true, mounted: false },
|
||||
{ label: 'Laputa', path: '/laputa', alias: 'laputa', available: true, mounted: true },
|
||||
@@ -261,6 +265,12 @@ describe('useVaultLoader', () => {
|
||||
rootPath: '/laputa',
|
||||
children: [{ name: 'laputa-projects', path: 'projects', rootPath: '/laputa', children: [] }],
|
||||
},
|
||||
{
|
||||
name: 'brian',
|
||||
path: '',
|
||||
rootPath: '/brian',
|
||||
children: [{ name: 'brian-projects', path: 'projects', rootPath: '/brian', children: [] }],
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -372,25 +382,15 @@ describe('useVaultLoader', () => {
|
||||
})
|
||||
|
||||
it('adds each mounted workspace as soon as that workspace finishes loading', async () => {
|
||||
let resolveLaputa: ((entries: VaultEntry[]) => void) | null = null
|
||||
const laputaLoad = createDeferred<VaultEntry[]>()
|
||||
const brian = { label: 'Brian', path: '/brian', alias: 'brian', available: true, mounted: true }
|
||||
const laputa = { label: 'Laputa', path: '/laputa', alias: 'laputa', available: true, mounted: true }
|
||||
const team = { label: 'Team', path: '/team', alias: 'team', available: true, mounted: true }
|
||||
const vaults = [brian, laputa, team]
|
||||
|
||||
backendInvokeFn.mockImplementation(((cmd: string, args?: Record<string, unknown>) => {
|
||||
const path = args?.path
|
||||
if (isVaultLoadCommand(cmd)) {
|
||||
if (path === '/laputa') {
|
||||
return new Promise<VaultEntry[]>((resolve) => {
|
||||
resolveLaputa = resolve
|
||||
})
|
||||
}
|
||||
return Promise.resolve([{ ...mockEntries[0], path: `${path}/note/hello.md` }])
|
||||
}
|
||||
if (cmd === 'list_vault_folders' || cmd === 'list_views' || cmd === 'get_modified_files') return Promise.resolve([])
|
||||
return Promise.resolve(null)
|
||||
}) as typeof defaultMockInvoke)
|
||||
backendInvokeFn.mockImplementation(buildMountedWorkspaceLoadMock({
|
||||
pendingEntriesByPath: { '/laputa': laputaLoad.promise },
|
||||
}))
|
||||
|
||||
const { result } = renderHook(() => useVaultLoader('/brian', vaults, '/brian', vaults))
|
||||
|
||||
@@ -399,7 +399,7 @@ describe('useVaultLoader', () => {
|
||||
})
|
||||
|
||||
await act(async () => {
|
||||
resolveLaputa?.([{ ...mockEntries[0], path: '/laputa/note/hello.md' }])
|
||||
laputaLoad.resolve([{ ...mockEntries[0], path: '/laputa/note/hello.md' }])
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -662,15 +662,17 @@ describe('useVaultLoader', () => {
|
||||
const brian = { label: 'Brian', path: '/brian', alias: 'brian', available: true, mounted: true }
|
||||
const laputa = { label: 'Laputa', path: '/laputa', alias: 'laputa', available: true, mounted: true }
|
||||
const vaults = [laputa, brian]
|
||||
const laputaStartupResponses: Partial<Record<string, VaultEntry[]>> = {
|
||||
reload_vault: [
|
||||
{ ...mockEntries[0], path: '/laputa/note/alpha.md', filename: 'alpha.md', title: 'Alpha' },
|
||||
],
|
||||
list_vault: [],
|
||||
}
|
||||
|
||||
backendInvokeFn.mockImplementation(((cmd: string, args?: Record<string, unknown>) => {
|
||||
if (cmd === 'reload_vault' && args?.path === '/laputa') {
|
||||
return Promise.resolve([
|
||||
{ ...mockEntries[0], path: '/laputa/note/alpha.md', filename: 'alpha.md', title: 'Alpha' },
|
||||
])
|
||||
}
|
||||
if (cmd === 'list_vault' && args?.path === '/laputa') return Promise.resolve([])
|
||||
if (cmd === 'list_vault_folders' || cmd === 'list_views' || cmd === 'get_modified_files') return Promise.resolve([])
|
||||
const response = args?.path === '/laputa' ? laputaStartupResponses[cmd] : undefined
|
||||
if (response) return Promise.resolve(response)
|
||||
if (EMPTY_ARRAY_COMMANDS.has(cmd)) return Promise.resolve([])
|
||||
return Promise.resolve(null)
|
||||
}) as typeof defaultMockInvoke)
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ export function loadVaultFolders({ vaultPath }: VaultPathOptions): Promise<Folde
|
||||
}
|
||||
|
||||
export async function loadMountedVaultFolders(options: MountedVaultFoldersOptions): Promise<FolderNode[]> {
|
||||
const mountedVaults = uniqueMountedVaults({ ...options, includeFallbackVault: false })
|
||||
const mountedVaults = uniqueMountedVaults(options)
|
||||
if (mountedVaults.length === 0) return []
|
||||
if (mountedVaults.length === 1) {
|
||||
const [vault] = mountedVaults
|
||||
@@ -213,7 +213,7 @@ export function loadVaultViews({ vaultPath }: VaultPathOptions): Promise<ViewFil
|
||||
}
|
||||
|
||||
export async function loadMountedVaultViews(options: MountedVaultViewsOptions): Promise<ViewFile[]> {
|
||||
const mountedVaults = uniqueMountedVaults({ ...options, includeFallbackVault: false })
|
||||
const mountedVaults = uniqueMountedVaults(options)
|
||||
if (mountedVaults.length === 0) return []
|
||||
if (mountedVaults.length === 1 && mountedVaults[0].path === options.vaultPath) {
|
||||
return loadVaultViews({ vaultPath: options.vaultPath })
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { loadMountedVaultViews } from './vaultLoaderCommands'
|
||||
import { loadMountedVaultFolders, loadMountedVaultViews } from './vaultLoaderCommands'
|
||||
import type { ViewDefinition } from '../types'
|
||||
|
||||
const mockInvoke = vi.fn()
|
||||
@@ -86,4 +86,93 @@ describe('loadMountedVaultViews', () => {
|
||||
|
||||
expect(views.map((view) => view.definition.name)).toEqual(['Default View', 'Mounted View'])
|
||||
})
|
||||
|
||||
it('loads saved views from the active workspace when folder vaults omit it', async () => {
|
||||
mockInvoke.mockImplementation((command: string, args?: Record<string, unknown>) => {
|
||||
if (command !== 'list_views') return Promise.resolve([])
|
||||
|
||||
if (args?.vaultPath === '/active') {
|
||||
return Promise.resolve([{ filename: 'active.yml', definition: viewDefinition('Active View') }])
|
||||
}
|
||||
if (args?.vaultPath === '/mounted') {
|
||||
return Promise.resolve([{ filename: 'mounted.yml', definition: viewDefinition('Mounted View') }])
|
||||
}
|
||||
throw new Error(`Unexpected vaultPath ${String(args?.vaultPath)}`)
|
||||
})
|
||||
|
||||
const views = await loadMountedVaultViews({
|
||||
defaultWorkspacePath: '/mounted',
|
||||
vaultPath: '/active',
|
||||
vaults: [
|
||||
{ label: 'Mounted', path: '/mounted', alias: 'mounted', mounted: true, available: true },
|
||||
],
|
||||
})
|
||||
|
||||
expect(views.map((view) => [view.definition.name, view.rootPath])).toEqual([
|
||||
['Mounted View', '/mounted'],
|
||||
['Active View', '/active'],
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('loadMountedVaultFolders', () => {
|
||||
beforeEach(() => {
|
||||
mockInvoke.mockReset()
|
||||
})
|
||||
|
||||
it('loads folders from the active workspace when folder vaults omit it', async () => {
|
||||
mockInvoke.mockImplementation((command: string, args?: Record<string, unknown>) => {
|
||||
if (command !== 'list_vault_folders') return Promise.resolve([])
|
||||
|
||||
const path = String(args?.path)
|
||||
if (path === '/active') {
|
||||
return Promise.resolve([{ name: 'active-folder', path: 'active-folder', children: [] }])
|
||||
}
|
||||
if (path === '/mounted') {
|
||||
return Promise.resolve([{ name: 'mounted-folder', path: 'mounted-folder', children: [] }])
|
||||
}
|
||||
throw new Error(`Unexpected path ${path}`)
|
||||
})
|
||||
|
||||
const folders = await loadMountedVaultFolders({
|
||||
defaultWorkspacePath: '/mounted',
|
||||
vaultPath: '/active',
|
||||
vaults: [
|
||||
{ label: 'Mounted', path: '/mounted', alias: 'mounted', mounted: true, available: true },
|
||||
],
|
||||
})
|
||||
|
||||
expect(folders).toEqual([
|
||||
{
|
||||
name: 'Mounted',
|
||||
path: '',
|
||||
rootPath: '/mounted',
|
||||
children: [{ name: 'mounted-folder', path: 'mounted-folder', rootPath: '/mounted', children: [] }],
|
||||
},
|
||||
{
|
||||
name: 'active',
|
||||
path: '',
|
||||
rootPath: '/active',
|
||||
children: [{ name: 'active-folder', path: 'active-folder', rootPath: '/active', children: [] }],
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('does not duplicate the active workspace when folder vaults already include it', async () => {
|
||||
mockInvoke.mockImplementation((command: string, args?: Record<string, unknown>) => {
|
||||
if (command !== 'list_vault_folders') return Promise.resolve([])
|
||||
return Promise.resolve([{ name: `${String(args?.path)}-folder`, path: 'folder', children: [] }])
|
||||
})
|
||||
|
||||
const folders = await loadMountedVaultFolders({
|
||||
defaultWorkspacePath: '/active',
|
||||
vaultPath: '/active',
|
||||
vaults: [
|
||||
{ label: 'Active', path: '/active', alias: 'active', mounted: true, available: true },
|
||||
],
|
||||
})
|
||||
|
||||
expect(mockInvoke).toHaveBeenCalledTimes(1)
|
||||
expect(folders).toEqual([{ name: '/active-folder', path: 'folder', children: [] }])
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user