fix(git): exit nested-repo states once resolution succeeds
NestedRepoResolutionStates had no success exit: on a non-repo root rootIsGitRepo stays false forever, so once repositories were found the pull-request and walkthrough tabs kept showing 'Checking repository' even after the selected repository probed as a repository. GitView never hit this because its call site sits inside its own isGitRepo === false branch. The component now takes the operating directory's probe and returns null when it resolves true. DiffView also still keyed its not-a-repository gate and every diff fetch off the raw project root, so opening a change from a nested repository showed 'This directory is not a Git repository'. It now resolves the nested repository for git data and diff operations while session-scoped lookups (session messages, review-flow directory) stay on the root.
This commit is contained in:
@@ -487,6 +487,7 @@ export const MobileChangesSurface: React.FC<MobileChangesSurfaceProps> = ({ onCl
|
|||||||
return renderListState(
|
return renderListState(
|
||||||
<NestedRepoResolutionStates
|
<NestedRepoResolutionStates
|
||||||
rootIsGitRepo={rootIsGitRepo}
|
rootIsGitRepo={rootIsGitRepo}
|
||||||
|
resolvedIsGitRepo={isGitRepo}
|
||||||
nestedRepos={nestedRepos}
|
nestedRepos={nestedRepos}
|
||||||
onRetryDiscovery={() => {
|
onRetryDiscovery={() => {
|
||||||
if (rootDirectory) void ensureNestedRepos(rootDirectory, { force: true });
|
if (rootDirectory) void ensureNestedRepos(rootDirectory, { force: true });
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
|
|
||||||
import { useUIStore } from '@/stores/useUIStore';
|
import { useUIStore } from '@/stores/useUIStore';
|
||||||
import { useEffectiveDirectory } from '@/hooks/useEffectiveDirectory';
|
import { useEffectiveDirectory } from '@/hooks/useEffectiveDirectory';
|
||||||
|
import { useNestedGitDirectory } from '@/hooks/useNestedGitDirectory';
|
||||||
import { useGitStore, useGitStatus, useIsGitRepo, useGitLoadingStatus } from '@/stores/useGitStore';
|
import { useGitStore, useGitStatus, useIsGitRepo, useGitLoadingStatus } from '@/stores/useGitStore';
|
||||||
import { useGitBaseBranchStore, gitBaseBranchEntryKey } from '@/stores/useGitBaseBranchStore';
|
import { useGitBaseBranchStore, gitBaseBranchEntryKey } from '@/stores/useGitBaseBranchStore';
|
||||||
import { coerceDiffScope, branchRangeKey, isBranchScopeAvailable, isBranchScopeDefinitelyUnavailable, useRangeKeyedCache, useBoundedDirectoryRetry } from './branchDiffScope';
|
import { coerceDiffScope, branchRangeKey, isBranchScopeAvailable, isBranchScopeDefinitelyUnavailable, useRangeKeyedCache, useBoundedDirectoryRetry } from './branchDiffScope';
|
||||||
@@ -997,7 +998,11 @@ export const DiffView: React.FC<DiffViewProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { git, files } = useRuntimeAPIs();
|
const { git, files } = useRuntimeAPIs();
|
||||||
const effectiveDirectory = useEffectiveDirectory();
|
const rootDirectory = useEffectiveDirectory();
|
||||||
|
// Diffs belong to the repository being diffed: when the root is not
|
||||||
|
// itself a repository, operate on the resolved nested repository instead.
|
||||||
|
const { gitDirectory: nestedGitDirectory } = useNestedGitDirectory(rootDirectory ?? null);
|
||||||
|
const effectiveDirectory = nestedGitDirectory ?? rootDirectory;
|
||||||
const openContextSurface = useUIStore((state) => state.openContextSurface);
|
const openContextSurface = useUIStore((state) => state.openContextSurface);
|
||||||
const requestWalkthroughSource = useWalkthroughStore((state) => state.requestSource);
|
const requestWalkthroughSource = useWalkthroughStore((state) => state.requestSource);
|
||||||
const { screenWidth, isMobile } = useDeviceInfo();
|
const { screenWidth, isMobile } = useDeviceInfo();
|
||||||
@@ -1038,7 +1043,7 @@ export const DiffView: React.FC<DiffViewProps> = ({
|
|||||||
const setDiffWrapLines = useUIStore((state) => state.setDiffWrapLines);
|
const setDiffWrapLines = useUIStore((state) => state.setDiffWrapLines);
|
||||||
const openContextFileAtLine = useUIStore((state) => state.openContextFileAtLine);
|
const openContextFileAtLine = useUIStore((state) => state.openContextFileAtLine);
|
||||||
const currentSessionId = useSessionUIStore((state) => state.currentSessionId);
|
const currentSessionId = useSessionUIStore((state) => state.currentSessionId);
|
||||||
const sessionMessages = useSessionMessages(currentSessionId ?? '', effectiveDirectory ?? undefined);
|
const sessionMessages = useSessionMessages(currentSessionId ?? '', rootDirectory ?? undefined);
|
||||||
const diffWrapLines = diffWrapLinesStore;
|
const diffWrapLines = diffWrapLinesStore;
|
||||||
const forcedStaged = activeDiffScope === 'staged' ? true : activeDiffScope === 'working' ? false : null;
|
const forcedStaged = activeDiffScope === 'staged' ? true : activeDiffScope === 'working' ? false : null;
|
||||||
const activeDiffStaged = forcedStaged ?? displayFileStaged;
|
const activeDiffStaged = forcedStaged ?? displayFileStaged;
|
||||||
@@ -1645,7 +1650,7 @@ export const DiffView: React.FC<DiffViewProps> = ({
|
|||||||
|
|
||||||
const handleStartReviewFlow = React.useCallback(async (execution: ReviewFlowExecution) => {
|
const handleStartReviewFlow = React.useCallback(async (execution: ReviewFlowExecution) => {
|
||||||
if (!currentSessionId) return;
|
if (!currentSessionId) return;
|
||||||
const directory = useSessionUIStore.getState().getDirectoryForSession(currentSessionId) || effectiveDirectory || '';
|
const directory = useSessionUIStore.getState().getDirectoryForSession(currentSessionId) || rootDirectory || '';
|
||||||
if (!directory) {
|
if (!directory) {
|
||||||
toast.error(t('diffView.reviewDialog.toast.noSessionDirectory'));
|
toast.error(t('diffView.reviewDialog.toast.noSessionDirectory'));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -2343,6 +2343,7 @@ export const GitView: React.FC<GitViewProps> = ({ isActive }) => {
|
|||||||
return (
|
return (
|
||||||
<NestedRepoResolutionStates
|
<NestedRepoResolutionStates
|
||||||
rootIsGitRepo={rootIsGitRepo}
|
rootIsGitRepo={rootIsGitRepo}
|
||||||
|
resolvedIsGitRepo={isGitRepo}
|
||||||
nestedRepos={nestedRepos}
|
nestedRepos={nestedRepos}
|
||||||
onRetryDiscovery={() => {
|
onRetryDiscovery={() => {
|
||||||
if (currentDirectory) {
|
if (currentDirectory) {
|
||||||
|
|||||||
@@ -265,6 +265,7 @@ export const PullRequestView: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<NestedRepoResolutionStates
|
<NestedRepoResolutionStates
|
||||||
rootIsGitRepo={rootIsGitRepo}
|
rootIsGitRepo={rootIsGitRepo}
|
||||||
|
resolvedIsGitRepo={isGitRepo}
|
||||||
nestedRepos={nestedRepos}
|
nestedRepos={nestedRepos}
|
||||||
onRetryDiscovery={() => {
|
onRetryDiscovery={() => {
|
||||||
void ensureNestedRepos(currentDirectory, { force: true });
|
void ensureNestedRepos(currentDirectory, { force: true });
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ import type { NestedRepoDiscovery } from '@/stores/useGitStore';
|
|||||||
type NestedRepoResolutionStatesProps = {
|
type NestedRepoResolutionStatesProps = {
|
||||||
/** Probe of the project root: `false` means nested resolution applies. */
|
/** Probe of the project root: `false` means nested resolution applies. */
|
||||||
rootIsGitRepo: boolean | null;
|
rootIsGitRepo: boolean | null;
|
||||||
|
/**
|
||||||
|
* Probe of the directory the consumer operates on (root or selected nested
|
||||||
|
* repository). `true` means resolution succeeded and the consumer should
|
||||||
|
* render its own content.
|
||||||
|
*/
|
||||||
|
resolvedIsGitRepo: boolean | null;
|
||||||
/** Discovery outcome for the root (`undefined` = not run yet). */
|
/** Discovery outcome for the root (`undefined` = not run yet). */
|
||||||
nestedRepos: NestedRepoDiscovery | undefined;
|
nestedRepos: NestedRepoDiscovery | undefined;
|
||||||
onRetryDiscovery: () => void;
|
onRetryDiscovery: () => void;
|
||||||
@@ -17,8 +23,9 @@ type NestedRepoResolutionStatesProps = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared empty/loading states for git surfaces while nested-repository
|
* Shared empty/loading states for git surfaces while nested-repository
|
||||||
* resolution is pending, failed, or impossible. Renders null once
|
* resolution is pending, failed, or impossible. Renders null once resolution
|
||||||
* repositories are resolved so the consumer can proceed into its own content.
|
* has finished — either the root is a repository or the operating directory
|
||||||
|
* probed as one — so the consumer can proceed into its own content.
|
||||||
*
|
*
|
||||||
* A runtime without the discovery route (VS Code) reports "unsupported": the
|
* A runtime without the discovery route (VS Code) reports "unsupported": the
|
||||||
* honest state there is the plain not-a-repository empty state, without a
|
* honest state there is the plain not-a-repository empty state, without a
|
||||||
@@ -26,6 +33,7 @@ type NestedRepoResolutionStatesProps = {
|
|||||||
*/
|
*/
|
||||||
export const NestedRepoResolutionStates: React.FC<NestedRepoResolutionStatesProps> = ({
|
export const NestedRepoResolutionStates: React.FC<NestedRepoResolutionStatesProps> = ({
|
||||||
rootIsGitRepo,
|
rootIsGitRepo,
|
||||||
|
resolvedIsGitRepo,
|
||||||
nestedRepos,
|
nestedRepos,
|
||||||
onRetryDiscovery,
|
onRetryDiscovery,
|
||||||
emptyStateFooter,
|
emptyStateFooter,
|
||||||
@@ -33,6 +41,7 @@ export const NestedRepoResolutionStates: React.FC<NestedRepoResolutionStatesProp
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
if (rootIsGitRepo !== false) return null;
|
if (rootIsGitRepo !== false) return null;
|
||||||
|
if (resolvedIsGitRepo === true) return null;
|
||||||
|
|
||||||
if (nestedRepos === undefined || nestedRepos === null) {
|
if (nestedRepos === undefined || nestedRepos === null) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -498,6 +498,7 @@ export const WalkthroughView = ({ directory: rootDirectory }: WalkthroughViewPro
|
|||||||
return (
|
return (
|
||||||
<NestedRepoResolutionStates
|
<NestedRepoResolutionStates
|
||||||
rootIsGitRepo={rootIsGitRepo}
|
rootIsGitRepo={rootIsGitRepo}
|
||||||
|
resolvedIsGitRepo={isGitRepo}
|
||||||
nestedRepos={nestedRepos}
|
nestedRepos={nestedRepos}
|
||||||
onRetryDiscovery={() => {
|
onRetryDiscovery={() => {
|
||||||
if (rootDirectory) void ensureNestedRepos(rootDirectory, { force: true });
|
if (rootDirectory) void ensureNestedRepos(rootDirectory, { force: true });
|
||||||
|
|||||||
Reference in New Issue
Block a user