diff --git a/app/src/components/intelligence/VaultPanel.test.tsx b/app/src/components/intelligence/VaultPanel.test.tsx index e44fc4c97..96e63c2b2 100644 --- a/app/src/components/intelligence/VaultPanel.test.tsx +++ b/app/src/components/intelligence/VaultPanel.test.tsx @@ -41,6 +41,8 @@ function vault(overrides: Record = {}) { created_at: '2026-05-17T10:00:00Z', last_synced_at: null, file_count: 0, + write_state: 'writable', + write_state_reason: 'writable', ...overrides, }; } @@ -111,6 +113,35 @@ describe('', () => { expect(screen.getByText('A')).toBeTruthy(); expect(screen.getByText(/42 file/)).toBeTruthy(); expect(screen.getByText(/synced 30s ago/)).toBeTruthy(); + expect(screen.getByTestId('vault-write-state-v-A')).toHaveTextContent('Writable'); + expect(screen.getByText(/Approved markdown/)).toBeTruthy(); + }); + + it('shows read-only and unavailable vault write states with reasons', async () => { + mockList.mockResolvedValueOnce({ + result: [ + vault({ + id: 'v-readonly', + name: 'Read only', + write_state: 'read_only', + write_state_reason: 'read_only', + }), + vault({ + id: 'v-missing', + name: 'Missing', + write_state: 'unavailable', + write_state_reason: 'unavailable', + }), + ], + logs: [], + }); + render(); + await waitFor(() => screen.getByTestId('vault-list')); + + expect(screen.getByTestId('vault-write-state-v-readonly')).toHaveTextContent('Read-only'); + expect(screen.getByText('Vault folder is read-only on this device.')).toBeTruthy(); + expect(screen.getByTestId('vault-write-state-v-missing')).toHaveTextContent('Unavailable'); + expect(screen.getByText('Vault folder is not available on this device.')).toBeTruthy(); }); it('toggles the add form and creates a vault on submit', async () => { diff --git a/app/src/components/intelligence/VaultPanel.tsx b/app/src/components/intelligence/VaultPanel.tsx index 9311a732e..e85b8d064 100644 --- a/app/src/components/intelligence/VaultPanel.tsx +++ b/app/src/components/intelligence/VaultPanel.tsx @@ -359,6 +359,12 @@ export function VaultPanel({ onToast }: VaultPanelProps) {
    {vaults.map(v => { const state = busy[v.id]; + const writeStateReason = v.write_state_reason + ? t( + `vault.writeState.reasons.${v.write_state_reason}`, + t('vault.writeState.unknownReason') + ) + : t('vault.writeState.unknownReason'); return (
  • @@ -379,6 +385,17 @@ export function VaultPanel({ onToast }: VaultPanelProps) { ) : t('vault.neverSynced')}
    +
    + + {t(`vault.writeState.${v.write_state}`)} + + + {writeStateReason} + +