From 63eedbdb91da2ded6f757c0c7c8d81539ea1d222 Mon Sep 17 00:00:00 2001 From: lucaronin Date: Tue, 7 Apr 2026 22:35:04 +0200 Subject: [PATCH] fix: clear missing active vault paths --- src/components/WelcomeScreen.test.tsx | 4 ++-- src/components/WelcomeScreen.tsx | 18 +-------------- src/hooks/useOnboarding.test.ts | 32 ++++++++++++++++++++++++++ src/hooks/useOnboarding.ts | 33 ++++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 20 deletions(-) diff --git a/src/components/WelcomeScreen.test.tsx b/src/components/WelcomeScreen.test.tsx index ac5f398c..23017b28 100644 --- a/src/components/WelcomeScreen.test.tsx +++ b/src/components/WelcomeScreen.test.tsx @@ -94,9 +94,9 @@ describe('WelcomeScreen', () => { expect(screen.getByText(/could not be found on disk/)).toBeInTheDocument() }) - it('shows the missing vault path in a badge', () => { + it('does not show the missing vault path in a badge', () => { render() - expect(screen.getByText('~/Laputa')).toBeInTheDocument() + expect(screen.queryByText('~/Laputa')).not.toBeInTheDocument() }) it('shows "Choose a different folder" instead of "Open existing vault"', () => { diff --git a/src/components/WelcomeScreen.tsx b/src/components/WelcomeScreen.tsx index b9446b1a..8ab7af7c 100644 --- a/src/components/WelcomeScreen.tsx +++ b/src/components/WelcomeScreen.tsx @@ -103,14 +103,6 @@ const OPTION_DESC_STYLE: React.CSSProperties = { marginTop: 2, } -const PATH_BADGE_STYLE: React.CSSProperties = { - width: '100%', - background: 'var(--sidebar)', - borderRadius: 6, - padding: '8px 12px', - textAlign: 'center', -} - const ERROR_STYLE: React.CSSProperties = { fontSize: 13, color: 'var(--destructive, #e03e3e)', @@ -155,7 +147,7 @@ function OptionButton({ icon, iconBg, label, description, onClick, disabled, loa ) } -export function WelcomeScreen({ mode, missingPath, defaultVaultPath, onCreateVault, onCreateNewVault, onOpenFolder, creating, error }: WelcomeScreenProps) { +export function WelcomeScreen({ mode, defaultVaultPath, onCreateVault, onCreateNewVault, onOpenFolder, creating, error }: WelcomeScreenProps) { const isWelcome = mode === 'welcome' return ( @@ -185,14 +177,6 @@ export function WelcomeScreen({ mode, missingPath, defaultVaultPath, onCreateVau

- {!isWelcome && missingPath && ( -
- - {missingPath} - -
- )} -
diff --git a/src/hooks/useOnboarding.test.ts b/src/hooks/useOnboarding.test.ts index 5c271f97..662215b6 100644 --- a/src/hooks/useOnboarding.test.ts +++ b/src/hooks/useOnboarding.test.ts @@ -87,6 +87,38 @@ describe('useOnboarding', () => { }) }) + it('clears the persisted active vault when the saved path no longer exists', async () => { + localStorage.setItem('laputa_welcome_dismissed', '1') + + mockInvokeFn.mockImplementation(async (cmd: string) => { + if (cmd === 'get_default_vault_path') return '/mock/Documents/Getting Started' + if (cmd === 'check_vault_exists') return false + if (cmd === 'load_vault_list') { + return { + vaults: [{ label: 'Old Vault', path: '/vault/deleted' }], + active_vault: '/vault/deleted', + hidden_defaults: [], + } + } + if (cmd === 'save_vault_list') return null + return null + }) + + const { result } = renderHook(() => useOnboarding('/vault/deleted')) + + await waitFor(() => { + expect(result.current.state.status).toBe('vault-missing') + }) + + expect(mockInvokeFn).toHaveBeenCalledWith('save_vault_list', { + list: { + vaults: [{ label: 'Old Vault', path: '/vault/deleted' }], + active_vault: null, + hidden_defaults: [], + }, + }) + }) + it('handleCreateVault creates vault and transitions to ready', async () => { mockInvokeFn.mockImplementation(async (cmd: string) => { if (cmd === 'get_default_vault_path') return '/mock/Documents/Getting Started' diff --git a/src/hooks/useOnboarding.ts b/src/hooks/useOnboarding.ts index fd768c29..cf7dd7d2 100644 --- a/src/hooks/useOnboarding.ts +++ b/src/hooks/useOnboarding.ts @@ -15,6 +15,12 @@ function tauriCall(command: string, args: Record): Promise + active_vault?: string | null + hidden_defaults?: string[] +} + function wasDismissed(): boolean { try { return localStorage.getItem(DISMISSED_KEY) === '1' @@ -31,6 +37,22 @@ function markDismissed(): void { } } +async function clearMissingActiveVault(missingPath: string): Promise { + try { + const list = await tauriCall('load_vault_list', {}) + if (!list || list.active_vault !== missingPath) return + await tauriCall('save_vault_list', { + list: { + vaults: list.vaults ?? [], + active_vault: null, + hidden_defaults: list.hidden_defaults ?? [], + }, + }) + } catch { + // Best effort only — onboarding should still proceed + } +} + export function useOnboarding(initialVaultPath: string) { const [state, setState] = useState({ status: 'loading' }) const [creating, setCreating] = useState(false) @@ -48,7 +70,16 @@ export function useOnboarding(initialVaultPath: string) { if (exists) { setState({ status: 'ready', vaultPath: initialVaultPath }) - } else if (wasDismissed()) { + } else { + await clearMissingActiveVault(initialVaultPath) + if (cancelled) return + } + + if (exists) { + return + } + + if (wasDismissed()) { // User previously dismissed — show vault-missing instead of welcome setState({ status: 'vault-missing', vaultPath: initialVaultPath, defaultPath }) } else {