diff --git a/src/renderer/src/components/new-workspace/SmartWorkspaceNameField.tsx b/src/renderer/src/components/new-workspace/SmartWorkspaceNameField.tsx index 4d65c87bd47..5a1ad4258c3 100644 --- a/src/renderer/src/components/new-workspace/SmartWorkspaceNameField.tsx +++ b/src/renderer/src/components/new-workspace/SmartWorkspaceNameField.tsx @@ -1081,7 +1081,7 @@ export default function SmartWorkspaceNameField({ } }, [rows]) - // Why: source rows lag debouncedQuery, so keep Enter off a stale row. + // Why: live input leads debounced search; freeze highlight until the query catches up. const valueWithinSourceLimit = isSmartWorkspaceSourceQueryWithinLimit(value) const debouncedQueryWithinSourceLimit = isSmartWorkspaceSourceQueryWithinLimit(debouncedQuery) const trimmedValue = valueWithinSourceLimit ? value.trim() : '' @@ -1151,10 +1151,8 @@ export default function SmartWorkspaceNameField({ const handleSelect = useCallback( (row: RowEntry) => { - // Why: provider rows can lag the live input; typed-name / create-branch stay safe. - if (isQueryStale && row.kind !== 'use-name' && row.kind !== 'create-branch') { - return - } + // Why: select what is shown — held provider rows stay visible while the + // query is ahead of debounce, so blocking them made click/Enter no-ops. if (row.kind === 'use-name' || row.kind === 'create-branch') { // Why: "create new branch" has no ref to base from, so it uses the typed-name path (default base). onValueChange(row.name) @@ -1170,14 +1168,7 @@ export default function SmartWorkspaceNameField({ } setOpen(false) }, - [ - isQueryStale, - onBranchSelect, - onGitHubItemSelect, - onGitLabItemSelect, - onLinearIssueSelect, - onValueChange - ] + [onBranchSelect, onGitHubItemSelect, onGitLabItemSelect, onLinearIssueSelect, onValueChange] ) const applyEmojiReplacement = useCallback( @@ -1609,19 +1600,12 @@ export default function SmartWorkspaceNameField({ } if (open && rows.length > 0) { const row = rows.find((entry) => entry.value === resolvedCommandValue) - if ( - row && - !( - isQueryStale && - row.kind !== 'use-name' && - row.kind !== 'create-branch' - ) - ) { + if (row) { event.preventDefault() handleSelect(row) return } - // No selectable row (stale provider arm); fall through to onPlainEnter. + // No highlighted row; fall through to onPlainEnter so the keypress isn't inert. } onPlainEnter?.() } diff --git a/src/renderer/src/components/new-workspace/smart-workspace-source-results.test.ts b/src/renderer/src/components/new-workspace/smart-workspace-source-results.test.ts index 8fd9744ded2..1a3709686f0 100644 --- a/src/renderer/src/components/new-workspace/smart-workspace-source-results.test.ts +++ b/src/renderer/src/components/new-workspace/smart-workspace-source-results.test.ts @@ -128,6 +128,45 @@ describe('Branch source results', () => { ).toEqual([{ refName: 'origin/feature', localBranchName: 'feature' }]) }) + it('keeps the last branch results while the user trims a prefix of the settled query', () => { + expect( + getVisibleBranchResults({ + mode: 'branches', + value: 'fe', + selectedRepoId: 'repo-1', + resultRepoId: 'repo-1', + resultQuery: 'feat', + branches: [{ refName: 'origin/feature', localBranchName: 'feature' }] + }) + ).toEqual([{ refName: 'origin/feature', localBranchName: 'feature' }]) + }) + + it('hides held branch results when the live query diverges from the settled query', () => { + expect( + getVisibleBranchResults({ + mode: 'branches', + value: 'bug', + selectedRepoId: 'repo-1', + resultRepoId: 'repo-1', + resultQuery: 'feat', + branches: [{ refName: 'origin/feature', localBranchName: 'feature' }] + }) + ).toEqual([]) + }) + + it('keeps held branch results across case-only edits of a prefix query', () => { + expect( + getVisibleBranchResults({ + mode: 'branches', + value: 'Feat', + selectedRepoId: 'repo-1', + resultRepoId: 'repo-1', + resultQuery: 'feat', + branches: [{ refName: 'origin/feature', localBranchName: 'feature' }] + }) + ).toEqual([{ refName: 'origin/feature', localBranchName: 'feature' }]) + }) + it('uses stable cmdk values for typed-text actions', () => { expect( buildSmartWorkspaceSourceRows({ diff --git a/src/shared/new-workspace/smart-workspace-source-results.ts b/src/shared/new-workspace/smart-workspace-source-results.ts index 127573ddd63..6e6d30c8859 100644 --- a/src/shared/new-workspace/smart-workspace-source-results.ts +++ b/src/shared/new-workspace/smart-workspace-source-results.ts @@ -99,9 +99,20 @@ export function getVisibleBranchResults({ if (!selectedRepoId || resultRepoId !== selectedRepoId || resultQuery === null) { return [] } - // Why: hold the last settled branch list while the user types ahead — blanking - // on query mismatch flashed the dropdown empty between keystrokes. - if (value.trim() === '' && resultQuery !== '') { + const currentQuery = value.trim() + // Why: hold the last settled list while the user extends/trims the query so the + // dropdown does not blank between debounced keystrokes. Drop the hold when the + // query diverges (e.g. "feat" → "bug") so unrelated rows do not linger. + if (currentQuery === '') { + return resultQuery === '' ? branches : [] + } + const currentQueryKey = currentQuery.toLowerCase() + const resultQueryKey = resultQuery.toLowerCase() + if ( + resultQueryKey !== currentQueryKey && + !currentQueryKey.startsWith(resultQueryKey) && + !resultQueryKey.startsWith(currentQueryKey) + ) { return [] } return branches