diff --git a/src/App.test.tsx b/src/App.test.tsx index 81e0d472..d3769f15 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -1015,6 +1015,32 @@ describe('App', () => { }) }) + it('clears the Git setup dialog when switching to a Git-enabled vault', async () => { + mockCommandResults.load_vault_list = { + vaults: [ + { label: 'Missing Git', path: '/work' }, + { label: 'Git Vault', path: '/vault-2' }, + ], + active_vault: '/work', + hidden_defaults: [], + } + mockCommandResults.is_git_repo = ({ vaultPath }: { vaultPath?: string } = {}) => vaultPath === '/vault-2' + + render() + + expect(await screen.findByText('Enable Git for this vault?')).toBeInTheDocument() + + fireEvent.click(screen.getByTestId('status-vault-trigger')) + fireEvent.click(screen.getByTestId('vault-menu-item-Git Vault')) + + await waitFor(() => { + expect(screen.getByTestId('status-vault-trigger')).toHaveTextContent('Git Vault') + }) + await waitFor(() => { + expect(screen.queryByText('Enable Git for this vault?')).not.toBeInTheDocument() + }) + }) + it('Cmd+1 hides sidebar and note list (editor-only mode)', async () => { render() await waitFor(() => { diff --git a/src/App.tsx b/src/App.tsx index 85a453ef..fe2fbf8e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -341,9 +341,15 @@ function App() { setShowGitSetupDialog(true) }, [gitRepoState, noteWindowParams, resolvedPath]) + useEffect(() => { + if (gitRepoState === 'missing') return + setShowGitSetupDialog(false) + }, [gitRepoState]) + const openGitSetupDialog = useCallback(() => { + if (gitRepoState !== 'missing') return setShowGitSetupDialog(true) - }, []) + }, [gitRepoState]) const dismissGitSetupDialog = useCallback(() => { dismissedGitSetupPathRef.current = resolvedPath @@ -893,6 +899,7 @@ function App() { }) const suggestedCommitMessage = useMemo(() => generateCommitMessage(vault.modifiedFiles), [vault.modifiedFiles]) const isGitVault = gitRepoState !== 'missing' + const shouldShowGitSetupDialog = !noteWindowParams && gitRepoState === 'missing' && showGitSetupDialog const modifiedFilesSignature = useMemo( () => vault.modifiedFiles.map((file) => `${file.relativePath}:${file.status}`).sort().join('|'), [vault.modifiedFiles], @@ -1505,7 +1512,7 @@ function App() { {sidebarVisible && ( <>
- +
@@ -1514,7 +1521,7 @@ function App() { <>
{effectiveSelection.kind === 'filter' && effectiveSelection.filter === 'pulse' ? ( - handleSetViewMode('all')} /> + handleSetViewMode('all')} locale={appLocale} /> ) : ( )} @@ -1579,13 +1586,14 @@ function App() { onKeepMine={conflictFlow.handleKeepMine} onKeepTheirs={conflictFlow.handleKeepTheirs} flushPendingRawContentRef={flushPendingRawContentRef} + locale={appLocale} />
- + - handleSetSelection({ kind: 'filter', filter: 'changes' })} onClickPulse={() => handleSetSelection({ kind: 'filter', filter: 'pulse' })} onCommitPush={handleCommitPush} onInitializeGit={openGitSetupDialog} isOffline={networkStatus.isOffline} isGitVault={isGitVault} syncStatus={autoSync.syncStatus} lastSyncTime={autoSync.lastSyncTime} conflictCount={autoSync.conflictFiles.length} remoteStatus={autoSync.remoteStatus} onTriggerSync={autoSync.triggerSync} onPullAndPush={autoSync.pullAndPush} onOpenConflictResolver={conflictFlow.handleOpenConflictResolver} zoomLevel={zoom.zoomLevel} themeMode={documentThemeMode} onZoomReset={zoom.zoomReset} onToggleThemeMode={settingsLoaded ? handleToggleThemeMode : undefined} buildNumber={buildNumber} onCheckForUpdates={handleCheckForUpdates} onRemoveVault={vaultSwitcher.removeVault} mcpStatus={mcpStatus} onInstallMcp={openMcpSetupDialog} aiAgentsStatus={aiAgentsStatus} vaultAiGuidanceStatus={vaultAiGuidanceStatus} defaultAiAgent={aiAgentPreferences.defaultAiAgent} onSetDefaultAiAgent={aiAgentPreferences.setDefaultAiAgent} onRestoreVaultAiGuidance={() => { void restoreVaultAiGuidance() }} /> - + handleSetSelection({ kind: 'filter', filter: 'changes' })} onClickPulse={() => handleSetSelection({ kind: 'filter', filter: 'pulse' })} onCommitPush={handleCommitPush} onInitializeGit={openGitSetupDialog} isOffline={networkStatus.isOffline} isGitVault={isGitVault} syncStatus={autoSync.syncStatus} lastSyncTime={autoSync.lastSyncTime} conflictCount={autoSync.conflictFiles.length} remoteStatus={autoSync.remoteStatus} onTriggerSync={autoSync.triggerSync} onPullAndPush={autoSync.pullAndPush} onOpenConflictResolver={conflictFlow.handleOpenConflictResolver} zoomLevel={zoom.zoomLevel} themeMode={documentThemeMode} onZoomReset={zoom.zoomReset} onToggleThemeMode={settingsLoaded ? handleToggleThemeMode : undefined} buildNumber={buildNumber} onCheckForUpdates={handleCheckForUpdates} onRemoveVault={vaultSwitcher.removeVault} mcpStatus={mcpStatus} onInstallMcp={openMcpSetupDialog} aiAgentsStatus={aiAgentsStatus} vaultAiGuidanceStatus={vaultAiGuidanceStatus} defaultAiAgent={aiAgentPreferences.defaultAiAgent} onSetDefaultAiAgent={aiAgentPreferences.setDefaultAiAgent} onRestoreVaultAiGuidance={() => { void restoreVaultAiGuidance() }} locale={appLocale} /> + setToastMessage(null)} /> diff --git a/src/components/AddPropertyForm.tsx b/src/components/AddPropertyForm.tsx index 6d2f38bb..4aa87982 100644 --- a/src/components/AddPropertyForm.tsx +++ b/src/components/AddPropertyForm.tsx @@ -12,6 +12,7 @@ import { } from '../utils/propertyTypes' import { StatusPill, StatusDropdown } from './StatusDropdown' import { DISPLAY_MODE_OPTIONS, DISPLAY_MODE_ICONS } from '../utils/propertyTypes' +import { translate, type AppLocale } from '../lib/i18n' function parseDateValue(value: string): Date | undefined { const iso = toISODate(value) @@ -39,7 +40,7 @@ function canSubmitProperty({ key, value, displayMode }: { key: string; value: st return displayMode !== 'number' || isValidNumberValue(value) } -function AddBooleanInput({ value, onChange }: { value: string; onChange: (v: string) => void }) { +function AddBooleanInput({ value, locale, onChange }: { value: string; locale: AppLocale; onChange: (v: string) => void }) { const boolVal = value.toLowerCase() === 'true' return ( ) } -function AddDateInput({ value, onChange }: { value: string; onChange: (v: string) => void }) { +function AddDateInput({ value, locale, onChange }: { value: string; locale: AppLocale; onChange: (v: string) => void }) { const selectedDate = value ? parseDateValue(value) : undefined const formatted = value ? formatDateValue(value) : '' return ( @@ -64,7 +65,7 @@ function AddDateInput({ value, onChange }: { value: string; onChange: (v: string > - {formatted || 'Pick a date\u2026'} + {formatted || translate(locale, 'inspector.properties.pickDate')} @@ -122,15 +123,16 @@ function AddNumberInput({ value, onChange, onKeyDown }: { ) } -function AddPropertyValueInput({ displayMode, value, onChange, onKeyDown, vaultStatuses }: { +function AddPropertyValueInput({ displayMode, value, onChange, onKeyDown, vaultStatuses, locale }: { displayMode: PropertyDisplayMode; value: string; onChange: (v: string) => void onKeyDown: (e: React.KeyboardEvent) => void; vaultStatuses: string[] + locale: AppLocale }) { switch (displayMode) { case 'number': return - case 'boolean': return - case 'date': return + case 'boolean': return + case 'date': return case 'status': return case 'tags': return ( ) default: return ( - onChange(e.target.value)} onKeyDown={onKeyDown} /> ) } } -export function AddPropertyForm({ onAdd, onCancel, vaultStatuses }: { +export function AddPropertyForm({ onAdd, onCancel, vaultStatuses, locale = 'en' }: { onAdd: (key: string, value: string, displayMode: PropertyDisplayMode) => void; onCancel: () => void vaultStatuses: string[] + locale?: AppLocale }) { const [newKey, setNewKey] = useState('') const [newValue, setNewValue] = useState('') @@ -169,7 +172,7 @@ export function AddPropertyForm({ onAdd, onCancel, vaultStatuses }: {
setNewKey(e.target.value)} onKeyDown={handleKeyDown} autoFocus /> - + -
diff --git a/src/components/AppLoadingSkeleton.tsx b/src/components/AppLoadingSkeleton.tsx index f24af454..386f6761 100644 --- a/src/components/AppLoadingSkeleton.tsx +++ b/src/components/AppLoadingSkeleton.tsx @@ -125,13 +125,7 @@ function SidebarGroupSkeleton({ rows, count }: { rows: string[]; count?: string function SidebarSkeleton() { return (