feat: vault management — remove vault from list and restore Getting Started

Add ability to remove vaults from the app list without deleting files on disk,
and restore the bundled Getting Started demo vault when needed.

Changes:
- Rust: add hidden_defaults field to VaultList for tracking removed default vaults
- useVaultSwitcher: add removeVault() and restoreGettingStarted() with auto-switch
- useCommandRegistry: add 'Remove Vault from List' and 'Restore Getting Started Vault' commands
- StatusBar: add X button per vault item in vault menu dropdown
- 25 new tests covering removal, restore, edge cases, and command palette

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Test
2026-03-03 02:26:41 +01:00
parent 2c5cfe2923
commit 5b1804e5e1
11 changed files with 769 additions and 21 deletions

View File

@@ -625,6 +625,93 @@ describe('useCommandRegistry', () => {
expect(result.current.find(c => c.id === 'open-theme-default')!.enabled).toBe(true)
})
})
describe('vault management commands', () => {
it('has remove-vault command in Settings group', () => {
const onRemoveActiveVault = vi.fn()
const { result } = renderHook(() => useCommandRegistry(makeConfig({
onRemoveActiveVault, vaultCount: 2,
})))
const cmd = result.current.find(c => c.id === 'remove-vault')
expect(cmd).toBeDefined()
expect(cmd!.label).toBe('Remove Vault from List')
expect(cmd!.group).toBe('Settings')
expect(cmd!.enabled).toBe(true)
})
it('disables remove-vault when only one vault remains', () => {
const onRemoveActiveVault = vi.fn()
const { result } = renderHook(() => useCommandRegistry(makeConfig({
onRemoveActiveVault, vaultCount: 1,
})))
expect(result.current.find(c => c.id === 'remove-vault')!.enabled).toBe(false)
})
it('disables remove-vault when onRemoveActiveVault is not provided', () => {
const { result } = renderHook(() => useCommandRegistry(makeConfig({ vaultCount: 3 })))
expect(result.current.find(c => c.id === 'remove-vault')!.enabled).toBe(false)
})
it('calls onRemoveActiveVault when remove-vault executes', () => {
const onRemoveActiveVault = vi.fn()
const { result } = renderHook(() => useCommandRegistry(makeConfig({
onRemoveActiveVault, vaultCount: 2,
})))
result.current.find(c => c.id === 'remove-vault')!.execute()
expect(onRemoveActiveVault).toHaveBeenCalled()
})
it('has restore-getting-started command in Settings group', () => {
const onRestoreGettingStarted = vi.fn()
const { result } = renderHook(() => useCommandRegistry(makeConfig({
onRestoreGettingStarted, isGettingStartedHidden: true,
})))
const cmd = result.current.find(c => c.id === 'restore-getting-started')
expect(cmd).toBeDefined()
expect(cmd!.label).toBe('Restore Getting Started Vault')
expect(cmd!.group).toBe('Settings')
expect(cmd!.enabled).toBe(true)
})
it('disables restore-getting-started when vault is not hidden', () => {
const onRestoreGettingStarted = vi.fn()
const { result } = renderHook(() => useCommandRegistry(makeConfig({
onRestoreGettingStarted, isGettingStartedHidden: false,
})))
expect(result.current.find(c => c.id === 'restore-getting-started')!.enabled).toBe(false)
})
it('calls onRestoreGettingStarted when restore command executes', () => {
const onRestoreGettingStarted = vi.fn()
const { result } = renderHook(() => useCommandRegistry(makeConfig({
onRestoreGettingStarted, isGettingStartedHidden: true,
})))
result.current.find(c => c.id === 'restore-getting-started')!.execute()
expect(onRestoreGettingStarted).toHaveBeenCalled()
})
it('remove-vault has relevant keywords for discoverability', () => {
const onRemoveActiveVault = vi.fn()
const { result } = renderHook(() => useCommandRegistry(makeConfig({
onRemoveActiveVault, vaultCount: 2,
})))
const cmd = result.current.find(c => c.id === 'remove-vault')
expect(cmd!.keywords).toContain('vault')
expect(cmd!.keywords).toContain('remove')
expect(cmd!.keywords).toContain('disconnect')
})
it('restore-getting-started has relevant keywords for discoverability', () => {
const onRestoreGettingStarted = vi.fn()
const { result } = renderHook(() => useCommandRegistry(makeConfig({
onRestoreGettingStarted, isGettingStartedHidden: true,
})))
const cmd = result.current.find(c => c.id === 'restore-getting-started')
expect(cmd!.keywords).toContain('vault')
expect(cmd!.keywords).toContain('restore')
expect(cmd!.keywords).toContain('demo')
})
})
})
describe('pluralizeType', () => {