diff --git a/desktop/src/components/shared/DirectoryPicker.test.tsx b/desktop/src/components/shared/DirectoryPicker.test.tsx
index eeb86578..5565c968 100644
--- a/desktop/src/components/shared/DirectoryPicker.test.tsx
+++ b/desktop/src/components/shared/DirectoryPicker.test.tsx
@@ -70,10 +70,42 @@ describe('DirectoryPicker', () => {
const trigger = screen.getByRole('button')
expect(trigger).toHaveTextContent('project')
- expect(trigger.className).toContain('rounded-lg')
+ expect(trigger.className).toContain('rounded-[7px]')
expect(trigger.className).not.toContain('rounded-full')
})
+ it('constrains long workbar project names without hiding the full path from hover users', () => {
+ const longProjectName = 'project-with-a-very-long-directory-name-that-should-not-stretch-the-launch-bar'
+ const longPath = `/workspace/${longProjectName}`
+
+ render(
+ ,
+ )
+
+ const trigger = screen.getByRole('button')
+ const label = screen.getByText(longProjectName)
+ expect(trigger).toHaveAttribute('title', longPath)
+ expect(trigger.className).toContain('w-full')
+ expect(label.className).toContain('truncate')
+ })
+
+ it('can show a Git icon for workbar projects before the recent-project cache is loaded', () => {
+ render(
+ ,
+ )
+
+ expect(screen.getByRole('button').querySelector('svg')).toBeInTheDocument()
+ })
+
it('renders browse entries without nesting interactive buttons', async () => {
vi.mocked(sessionsApi.getRecentProjects).mockResolvedValue({ projects: [] })
vi.mocked(filesystemApi.browse).mockResolvedValue({
diff --git a/desktop/src/components/shared/DirectoryPicker.tsx b/desktop/src/components/shared/DirectoryPicker.tsx
index e4b15fdf..124977bf 100644
--- a/desktop/src/components/shared/DirectoryPicker.tsx
+++ b/desktop/src/components/shared/DirectoryPicker.tsx
@@ -8,6 +8,7 @@ type Props = {
value: string
onChange: (path: string) => void
variant?: 'chip' | 'workbar'
+ isGitProject?: boolean
}
type DirEntry = { name: string; path: string; isDirectory: boolean }
@@ -29,7 +30,7 @@ function projectNameFromPath(filePath: string) {
return displayRoot.split('/').filter(Boolean).pop() || filePath
}
-export function DirectoryPicker({ value, onChange, variant = 'chip' }: Props) {
+export function DirectoryPicker({ value, onChange, variant = 'chip', isGitProject = false }: Props) {
const t = useTranslation()
const [isOpen, setIsOpen] = useState(false)
const [mode, setMode] = useState<'recent' | 'browse'>('recent')
@@ -146,42 +147,46 @@ export function DirectoryPicker({ value, onChange, variant = 'chip' }: Props) {
// Find selected project info
const selectedProject = projects.find((p) => p.realPath === value)
const isWorkbar = variant === 'workbar'
+ const selectedLabel = selectedProject?.repoName || selectedProject?.projectName || projectNameFromPath(value)
+ const showGitIcon = selectedProject?.isGit || isGitProject
const triggerClassName = isWorkbar
- ? 'flex min-w-0 max-w-full items-center gap-2 rounded-lg px-2.5 py-2 text-sm font-medium text-[var(--color-text-secondary)] transition-colors hover:bg-[var(--color-surface-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-brand)]/35'
+ ? 'flex h-9 w-full min-w-0 items-center gap-1.5 rounded-[7px] border border-transparent px-2.5 text-[13px] font-medium leading-none text-[var(--color-text-secondary)] transition-colors hover:border-[var(--color-border)] hover:bg-[var(--color-surface-container-lowest)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-brand)]/35'
: 'flex items-center gap-2 px-3 py-1.5 bg-[var(--color-surface-container-low)] hover:bg-[var(--color-surface-hover)] rounded-full text-xs transition-colors border border-[var(--color-border)]'
const emptyTriggerClassName = isWorkbar
- ? 'flex min-w-0 items-center gap-2 rounded-lg px-2.5 py-2 text-sm font-medium text-[var(--color-text-secondary)] transition-colors hover:bg-[var(--color-surface-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-brand)]/35'
+ ? 'flex h-9 min-w-0 items-center gap-1.5 rounded-[7px] border border-transparent px-2.5 text-[13px] font-medium leading-none text-[var(--color-text-secondary)] transition-colors hover:border-[var(--color-border)] hover:bg-[var(--color-surface-container-lowest)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-brand)]/35'
: 'flex items-center gap-2 text-xs text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] transition-colors'
return (
-
+
{/* Trigger — shows selected project chip or placeholder */}
{value ? (
) : (
)}
diff --git a/desktop/src/components/shared/RepositoryLaunchControls.tsx b/desktop/src/components/shared/RepositoryLaunchControls.tsx
index 524fc448..184c1b94 100644
--- a/desktop/src/components/shared/RepositoryLaunchControls.tsx
+++ b/desktop/src/components/shared/RepositoryLaunchControls.tsx
@@ -256,15 +256,16 @@ export function RepositoryLaunchControls({
onLaunchReadyChange?.(isLaunchReady)
}, [isLaunchReady, onLaunchReadyChange])
- const workbarButtonClassName = 'inline-flex min-w-0 items-center gap-2 rounded-lg px-2.5 py-2 text-sm font-medium text-[var(--color-text-secondary)] transition-colors hover:bg-[var(--color-surface-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-brand)]/35 disabled:cursor-not-allowed disabled:opacity-50'
+ const worktreeLabel = useWorktree ? t('repoLaunch.worktreeIsolated') : t('repoLaunch.worktreeCurrent')
+ const workbarButtonClassName = 'group inline-flex h-9 min-w-0 items-center gap-1.5 rounded-[7px] border border-transparent px-2.5 text-[13px] font-medium leading-none text-[var(--color-text-secondary)] transition-colors hover:border-[var(--color-border)] hover:bg-[var(--color-surface-container-lowest)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-brand)]/35 disabled:cursor-not-allowed disabled:opacity-50'
return (
-
-
+
+
{loading && workDir && (
-
+
{t('common.loading')}
@@ -272,7 +273,7 @@ export function RepositoryLaunchControls({
{isGitReady && (
<>
-
+
>