mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-17 13:13:35 +08:00
fix: avoid treating normal folders as repository warnings
Non-Git folders are valid launch targets for desktop sessions, so the composer should not render them as an inline repository warning. The branch and worktree controls remain hidden outside Git repositories while server-side repository validation still protects actual branch-launch requests. Constraint: Non-Git directories must remain usable as ordinary session workdirs. Rejected: Keep the inline not-Git warning | it reads like an error even though the user can continue normally. Confidence: high Scope-risk: narrow Directive: Keep dirty-worktree and checked-out-branch warnings visible because those still require a launch-mode decision. Tested: cd desktop && bun run test -- --run src/pages/EmptySession.test.tsx src/components/chat/ChatInput.test.tsx Tested: bun run check:desktop Tested: git diff --check -- desktop/src/components/shared/RepositoryLaunchControls.tsx desktop/src/pages/EmptySession.test.tsx desktop/src/i18n/locales/en.ts desktop/src/i18n/locales/zh.ts Not-tested: Native Tauri packaged window visual check
This commit is contained in:
parent
eadbd4be14
commit
592ace93d0
@ -37,7 +37,7 @@ const VIEWPORT_GUTTER = 12
|
||||
function stateMessage(context: RepositoryContextResult | null, error: string | null) {
|
||||
if (error) return error
|
||||
if (!context) return null
|
||||
if (context.state === 'not_git_repo') return 'not_git'
|
||||
if (context.state === 'not_git_repo') return null
|
||||
if (context.state === 'missing_workdir') return 'missing'
|
||||
if (context.state === 'error') return context.error || 'error'
|
||||
return null
|
||||
@ -370,9 +370,7 @@ export function RepositoryLaunchControls({
|
||||
<div className="flex items-center gap-2 px-1 text-[11px] text-[var(--color-text-tertiary)]">
|
||||
<AlertCircle size={13} className="shrink-0" />
|
||||
<span>
|
||||
{message === 'not_git'
|
||||
? t('repoLaunch.notGit')
|
||||
: message === 'missing'
|
||||
{message === 'missing'
|
||||
? t('repoLaunch.missingWorkdir')
|
||||
: message}
|
||||
</span>
|
||||
|
||||
@ -706,7 +706,6 @@ export const en = {
|
||||
'repoLaunch.worktreeCurrent': 'Current worktree',
|
||||
'repoLaunch.worktreeIsolated': 'Isolated worktree',
|
||||
'repoLaunch.selectWorktree': 'Select worktree mode',
|
||||
'repoLaunch.notGit': 'Current project is not a Git repository.',
|
||||
'repoLaunch.missingWorkdir': 'Working directory is missing.',
|
||||
'repoLaunch.dirtyWarning': 'Uncommitted changes detected. Direct switching will be blocked; enable isolated worktree to continue without touching this folder.',
|
||||
'repoLaunch.checkedOutWarning': 'This branch is already checked out elsewhere. Enable isolated worktree or choose another branch.',
|
||||
|
||||
@ -708,7 +708,6 @@ export const zh: Record<TranslationKey, string> = {
|
||||
'repoLaunch.worktreeCurrent': '当前工作树',
|
||||
'repoLaunch.worktreeIsolated': '独立工作树',
|
||||
'repoLaunch.selectWorktree': '选择工作树模式',
|
||||
'repoLaunch.notGit': '当前项目不是 Git 仓库。',
|
||||
'repoLaunch.missingWorkdir': '工作目录不存在。',
|
||||
'repoLaunch.dirtyWarning': '检测到未提交变更,直接切换会被阻止。开启独立工作树即可继续,且不会改动当前目录。',
|
||||
'repoLaunch.checkedOutWarning': '这个分支已在其他工作树中检出。请开启独立工作树或选择其他分支。',
|
||||
|
||||
@ -103,6 +103,20 @@ function okRepositoryContext(overrides: Partial<RepositoryContextResult> = {}):
|
||||
}
|
||||
}
|
||||
|
||||
function notGitRepositoryContext(): RepositoryContextResult {
|
||||
return {
|
||||
state: 'not_git_repo',
|
||||
workDir: '/workspace/project',
|
||||
repoRoot: null,
|
||||
repoName: null,
|
||||
currentBranch: null,
|
||||
defaultBranch: null,
|
||||
dirty: false,
|
||||
branches: [],
|
||||
worktrees: [],
|
||||
}
|
||||
}
|
||||
|
||||
describe('EmptySession', () => {
|
||||
const initialSessionState = useSessionStore.getInitialState()
|
||||
const initialChatState = useChatStore.getInitialState()
|
||||
@ -199,6 +213,33 @@ describe('EmptySession', () => {
|
||||
expect(mocks.wsConnect).toHaveBeenCalledWith('draft-session')
|
||||
})
|
||||
|
||||
it('starts in a selected non-Git project without showing a repository warning', async () => {
|
||||
mocks.getRepositoryContext.mockResolvedValueOnce(notGitRepositoryContext())
|
||||
|
||||
render(<EmptySession />)
|
||||
|
||||
fireEvent.change(screen.getByRole('textbox'), {
|
||||
target: { value: 'draft question', selectionStart: 14 },
|
||||
})
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Pick project' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('button', { name: /Run/i })).not.toBeDisabled()
|
||||
})
|
||||
|
||||
expect(screen.queryByText('Current project is not a Git repository.')).not.toBeInTheDocument()
|
||||
expect(screen.queryByRole('button', { name: /Select branch:/ })).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('Current worktree')).not.toBeInTheDocument()
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /Run/i }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mocks.createSession).toHaveBeenCalledWith({
|
||||
workDir: '/workspace/project',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('shows an actionable repository error when direct branch switching is blocked', async () => {
|
||||
mocks.createSession.mockRejectedValueOnce(new ApiError(400, {
|
||||
error: 'REPOSITORY_DIRTY_WORKTREE',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user