fix(git): resolve blank nested-repo surfaces; add repository pickers

The resolution gate on the pull-request, walkthrough, and mobile changes
surfaces stayed on forever (rootIsGitRepo stays false on a non-repo
root) while NestedRepoResolutionStates exits once the selected
repository probes as a repository, so those surfaces rendered nothing.
The gate now shows resolution states only while the operating directory
has not proven to be a repository, matching GitView.

Extract GitHeader's repository switcher into git/NestedRepoPicker and
mount it in the diff toolbar, a new slim header in the pull-request
view, the walkthrough header, and the mobile changes header. The pick
is shared per root, so every surface follows.

The walkthrough tab mounts keep-alive and hidden; it now receives a
visible prop so discovery waits until the tab is actually opened. Add
component tests for the shared resolution states.
This commit is contained in:
jaygupta17
2026-08-25 20:47:02 +05:30
parent e26b55e067
commit 11a48958e8
9 changed files with 241 additions and 67 deletions
@@ -12,12 +12,7 @@ import type { IconName } from "@/components/icon/icons";
import { BranchSelector } from './BranchSelector';
import { WorktreeBranchDisplay } from './WorktreeBranchDisplay';
import { SyncActions } from './SyncActions';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
} from '@/components/ui/select';
import { NestedRepoPicker } from './NestedRepoPicker';
import type {
GitStatus,
GitIdentityProfile,
@@ -282,11 +277,6 @@ export const GitHeader: React.FC<GitHeaderProps> = ({
}
const repositoryOptionsForPicker = (repositoryOptions ?? []).filter(Boolean);
const repositoryRelativePath = (repository: string): string => {
const rootPrefix = `${repositoryRoot ?? ''}/`;
return repository.startsWith(rootPrefix) ? repository.slice(rootPrefix.length) : repository;
};
const repositoryLabel = selectedRepository ? repositoryRelativePath(selectedRepository) : '';
const managementButtons = (
<div className="flex items-center gap-1 shrink-0">
@@ -451,33 +441,13 @@ export const GitHeader: React.FC<GitHeaderProps> = ({
remotes={remotes}
/>
)}
{repositoryOptionsForPicker.length > 0 ? (
<Select
value={selectedRepository ?? undefined}
onValueChange={(value) => {
if (value && onSelectRepository) {
onSelectRepository(value);
}
}}
>
<SelectTrigger
size="sm"
className="max-w-[13rem] gap-1.5 px-2 py-1"
aria-label={t('gitView.empty.selectRepositoryPlaceholder')}
>
<Icon name="folder-3" className="size-4 text-muted-foreground" />
<span className="min-w-0 truncate font-medium text-left">
{repositoryLabel}
</span>
</SelectTrigger>
<SelectContent align="start">
{repositoryOptionsForPicker.map((repository) => (
<SelectItem key={repository} value={repository}>
<span className="truncate">{repositoryRelativePath(repository)}</span>
</SelectItem>
))}
</SelectContent>
</Select>
{repositoryOptionsForPicker.length > 0 && onSelectRepository ? (
<NestedRepoPicker
repositories={repositoryOptionsForPicker}
selectedRepository={selectedRepository ?? null}
onSelectRepository={onSelectRepository}
repositoryRoot={repositoryRoot}
/>
) : null}
</div>
<div className="flex shrink-0 items-center gap-1">