feat(code): project pickers on quill autocomplete#2103
Conversation
Prompt To Fix All With AIFix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
apps/code/src/renderer/features/sidebar/components/ProjectSwitcher.tsx:286-291
Query not reset when a project is selected via click or Enter. `handleProjectSelect` calls `setDialogOpen(false)` directly on the parent state, bypassing `handleOpenChange`, so `setQuery("")` is never reached. Compare with `FilePicker.handleSelect` which explicitly calls `handleOpenChange(false)`. The test plan says "Reopening the dialog clears the previous query" — that only holds for Escape/overlay closes today, not for project selection.
```suggestion
const handleSelect = (id: string | null) => {
if (id === null) return;
const projectId = Number(id);
if (Number.isNaN(projectId)) return;
handleProjectSelect(projectId);
setQuery("");
};
```
### Issue 2 of 2
apps/code/src/renderer/features/onboarding/components/ProjectSelect.tsx:40-46
Same issue as `ProjectSwitcher`: when a project is selected, `setOpen(false)` changes the controlled `open` state directly, so Radix UI's Popover does not fire `onOpenChange` and `setQuery("")` is never reached. If the user re-opens the picker after a selection, the previous search string is still visible. Routing through `handleOpenChange` ensures the query is always cleared on any close path.
```suggestion
const handleSelect = (id: string | null) => {
if (id === null) return;
const next = Number(id);
if (Number.isNaN(next)) return;
onProjectChange(next);
handleOpenChange(false);
};
```
Reviews (1): Last reviewed commit: "feat(code): project pickers on quill aut..." | Re-trigger Greptile |
| const handleSelect = (id: string | null) => { | ||
| if (id === null) return; | ||
| const projectId = Number(id); | ||
| if (Number.isNaN(projectId)) return; | ||
| handleProjectSelect(projectId); | ||
| }; |
There was a problem hiding this comment.
Query not reset when a project is selected via click or Enter.
handleProjectSelect calls setDialogOpen(false) directly on the parent state, bypassing handleOpenChange, so setQuery("") is never reached. Compare with FilePicker.handleSelect which explicitly calls handleOpenChange(false). The test plan says "Reopening the dialog clears the previous query" — that only holds for Escape/overlay closes today, not for project selection.
| const handleSelect = (id: string | null) => { | |
| if (id === null) return; | |
| const projectId = Number(id); | |
| if (Number.isNaN(projectId)) return; | |
| handleProjectSelect(projectId); | |
| }; | |
| const handleSelect = (id: string | null) => { | |
| if (id === null) return; | |
| const projectId = Number(id); | |
| if (Number.isNaN(projectId)) return; | |
| handleProjectSelect(projectId); | |
| setQuery(""); | |
| }; |
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/sidebar/components/ProjectSwitcher.tsx
Line: 286-291
Comment:
Query not reset when a project is selected via click or Enter. `handleProjectSelect` calls `setDialogOpen(false)` directly on the parent state, bypassing `handleOpenChange`, so `setQuery("")` is never reached. Compare with `FilePicker.handleSelect` which explicitly calls `handleOpenChange(false)`. The test plan says "Reopening the dialog clears the previous query" — that only holds for Escape/overlay closes today, not for project selection.
```suggestion
const handleSelect = (id: string | null) => {
if (id === null) return;
const projectId = Number(id);
if (Number.isNaN(projectId)) return;
handleProjectSelect(projectId);
setQuery("");
};
```
How can I resolve this? If you propose a fix, please make it concise.
jonathanlab
left a comment
There was a problem hiding this comment.
Nice! Seems like these components have a bunch of duplicated logic w.r.t. input handling (see handleOpenChange and handleSelect), could we deduplicate that?
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
e33ce98 to
9095035
Compare
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Avoids rendering `No projects match ""` when the picker opens with no projects available. Addresses review comment on PR #2103. Generated-By: PostHog Code Task-Id: c5674c04-c95c-4bfe-bfcf-248a921b4aae
1e34788 to
cca2f3e
Compare
- Move Check (use typed name) and Refresh buttons inside ComboboxInput as InputGroupAddon/InputGroupButton — they now sit inside the input border instead of as detached squares - Make ComboboxInput a direct child of ComboboxContent so quill's `.quill-combobox__content > [data-slot=combobox-input-group-wrapper]` rule applies p-1 padding + border-bottom (fixes "funky" layout) - Render "Create new branch" as a sentinel ComboboxItem inside ComboboxListFooter, following the combobox.stories.tsx InputInsidePopupWithFooter pattern — keyboard-navigable, sticky bottom - Drop pe-2 on ComboboxList so the scroll container is full-width - Use variant="outline" on the Check InputGroupButton
ProjectSwitcher's handleProjectSelect calls setDialogOpen(false) directly on parent state, which doesn't fire the Dialog's onOpenChange — so the inner handleOpenChange (where setQuery resets) was skipped on selection. Reset the query inline in handleSelect. ProjectSelect's handleSelect called setOpen(false) directly, bypassing Popover's onOpenChange the same way. Route through handleOpenChange. Both addressed by greptile P1 comments on #2103.
Summary
ProjectSwitcher(sidebar "Change project" dialog) andProjectSelect(onboarding inline picker) fromcmdk(via theCommand.tsxwrapper) to quillAutocomplete*.ProjectSwitchernow uses quillDialog+DialogContent(matchesCommandMenu/FilePicker); orgs render as labeled groups when there are 2+ orgs, otherwise unlabeled.ProjectSelectkeeps the RadixPopoverhost (anchored to the inline "change" trigger), Autocomplete is rendered inline inside.inline + defaultOpen + autoHighlight="always"pattern, customfilterfor case-insensitive name matching,AutocompleteStatusempty content,CommandKeyHintsfooter on the dialog variant.Command.tsxwrapper +Command.css, plus the cmdk-targetedProjectSwitcher.css/ProjectSelect.css.Stacked on #2101 (
ux/file-picker-quill) which is stacked on #2100 (ux/cmd-menu). Merge order: #2100 → #2101 → this.What's left on cmdk
components/ui/combobox/Combobox.tsx+useComboboxFilter.ts(standalone reusable Combobox)features/folder-picker/components/GitHubRepoPicker.tsx(only importsdefaultFilterfrom cmdk)Both can move to a follow-up PR (likely against quill's
Combobox*namespace, separate fromAutocomplete*).Test plan
ProjectSwitcher(sidebar bottom-left → "Change project")No projects match "xyz"shows when filter is empty.ProjectSelect(onboarding "change" link next to project name)onProjectChangefires with the picked id.disabledprop dims the trigger and prevents clicks.Regressions / general
pnpm --filter code typecheckclean.