Skip to content

Commit 955ef7e

Browse files
committed
feat: conditionally show search bar in ApiConfigSelector only when > 6 items
- Show search bar only when there are more than 6 API configurations - Display info blurb in place of search bar when 6 or fewer configs - Hide info icon when showing the info blurb to avoid duplication - Update tests to handle conditional rendering of search functionality
1 parent 94f7001 commit 955ef7e

File tree

2 files changed

+141
-32
lines changed

2 files changed

+141
-32
lines changed

webview-ui/src/components/chat/ApiConfigSelector.tsx

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -158,25 +158,33 @@ export const ApiConfigSelector = ({
158158
container={portalContainer}
159159
className="p-0 overflow-hidden w-[300px]">
160160
<div className="flex flex-col w-full">
161-
{/* Search input */}
162-
<div className="relative p-2 border-b border-vscode-dropdown-border">
163-
<input
164-
aria-label={t("common:ui.search_placeholder")}
165-
value={searchValue}
166-
onChange={(e) => setSearchValue(e.target.value)}
167-
placeholder={t("common:ui.search_placeholder")}
168-
className="w-full h-8 px-2 py-1 text-xs bg-vscode-input-background text-vscode-input-foreground border border-vscode-input-border rounded focus:outline-0"
169-
autoFocus
170-
/>
171-
{searchValue.length > 0 && (
172-
<div className="absolute right-4 top-0 bottom-0 flex items-center justify-center">
173-
<X
174-
className="text-vscode-input-foreground opacity-50 hover:opacity-100 size-4 p-0.5 cursor-pointer"
175-
onClick={() => setSearchValue("")}
176-
/>
177-
</div>
178-
)}
179-
</div>
161+
{/* Search input or info blurb */}
162+
{listApiConfigMeta.length > 6 ? (
163+
<div className="relative p-2 border-b border-vscode-dropdown-border">
164+
<input
165+
aria-label={t("common:ui.search_placeholder")}
166+
value={searchValue}
167+
onChange={(e) => setSearchValue(e.target.value)}
168+
placeholder={t("common:ui.search_placeholder")}
169+
className="w-full h-8 px-2 py-1 text-xs bg-vscode-input-background text-vscode-input-foreground border border-vscode-input-border rounded focus:outline-0"
170+
autoFocus
171+
/>
172+
{searchValue.length > 0 && (
173+
<div className="absolute right-4 top-0 bottom-0 flex items-center justify-center">
174+
<X
175+
className="text-vscode-input-foreground opacity-50 hover:opacity-100 size-4 p-0.5 cursor-pointer"
176+
onClick={() => setSearchValue("")}
177+
/>
178+
</div>
179+
)}
180+
</div>
181+
) : (
182+
<div className="p-3 border-b border-vscode-dropdown-border">
183+
<p className="text-xs text-vscode-descriptionForeground m-0">
184+
{t("prompts:apiConfiguration.select")}
185+
</p>
186+
</div>
187+
)}
180188

181189
{/* Config list */}
182190
<div className="max-h-[300px] overflow-y-auto">
@@ -212,9 +220,11 @@ export const ApiConfigSelector = ({
212220

213221
{/* Info icon and title on the right with matching spacing */}
214222
<div className="flex items-center gap-1 pr-1">
215-
<StandardTooltip content={t("prompts:apiConfiguration.select")}>
216-
<span className="codicon codicon-info text-xs text-vscode-descriptionForeground opacity-70 hover:opacity-100 cursor-help" />
217-
</StandardTooltip>
223+
{listApiConfigMeta.length > 6 && (
224+
<StandardTooltip content={t("prompts:apiConfiguration.select")}>
225+
<span className="codicon codicon-info text-xs text-vscode-descriptionForeground opacity-70 hover:opacity-100 cursor-help" />
226+
</StandardTooltip>
227+
)}
218228
<h4 className="m-0 font-medium text-sm text-vscode-descriptionForeground">
219229
{t("prompts:apiConfiguration.title")}
220230
</h4>

webview-ui/src/components/chat/__tests__/ApiConfigSelector.spec.tsx

Lines changed: 109 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,20 @@ describe("ApiConfigSelector", () => {
115115
expect(popoverContent).toBeInTheDocument()
116116
})
117117

118-
test("renders search input when popover is open", () => {
119-
render(<ApiConfigSelector {...defaultProps} />)
118+
test("renders search input when popover is open and more than 6 configs", () => {
119+
const props = {
120+
...defaultProps,
121+
listApiConfigMeta: [
122+
{ id: "config1", name: "Config 1" },
123+
{ id: "config2", name: "Config 2" },
124+
{ id: "config3", name: "Config 3" },
125+
{ id: "config4", name: "Config 4" },
126+
{ id: "config5", name: "Config 5" },
127+
{ id: "config6", name: "Config 6" },
128+
{ id: "config7", name: "Config 7" },
129+
],
130+
}
131+
render(<ApiConfigSelector {...props} />)
120132

121133
const trigger = screen.getByTestId("dropdown-trigger")
122134
fireEvent.click(trigger)
@@ -125,12 +137,36 @@ describe("ApiConfigSelector", () => {
125137
expect(searchInput).toBeInTheDocument()
126138
})
127139

128-
test("filters configs based on search input", async () => {
140+
test("renders info blurb instead of search when 6 or fewer configs", () => {
129141
render(<ApiConfigSelector {...defaultProps} />)
130142

131143
const trigger = screen.getByTestId("dropdown-trigger")
132144
fireEvent.click(trigger)
133145

146+
// Should not have search input
147+
expect(screen.queryByPlaceholderText("common:ui.search_placeholder")).not.toBeInTheDocument()
148+
// Should have info blurb
149+
expect(screen.getByText("prompts:apiConfiguration.select")).toBeInTheDocument()
150+
})
151+
152+
test("filters configs based on search input", async () => {
153+
const props = {
154+
...defaultProps,
155+
listApiConfigMeta: [
156+
{ id: "config1", name: "Config 1" },
157+
{ id: "config2", name: "Config 2" },
158+
{ id: "config3", name: "Config 3" },
159+
{ id: "config4", name: "Config 4" },
160+
{ id: "config5", name: "Config 5" },
161+
{ id: "config6", name: "Config 6" },
162+
{ id: "config7", name: "Config 7" },
163+
],
164+
}
165+
render(<ApiConfigSelector {...props} />)
166+
167+
const trigger = screen.getByTestId("dropdown-trigger")
168+
fireEvent.click(trigger)
169+
134170
const searchInput = screen.getByPlaceholderText("common:ui.search_placeholder")
135171
fireEvent.change(searchInput, { target: { value: "Config 2" } })
136172

@@ -144,7 +180,19 @@ describe("ApiConfigSelector", () => {
144180
})
145181

146182
test("shows no results message when search has no matches", async () => {
147-
render(<ApiConfigSelector {...defaultProps} />)
183+
const props = {
184+
...defaultProps,
185+
listApiConfigMeta: [
186+
{ id: "config1", name: "Config 1" },
187+
{ id: "config2", name: "Config 2" },
188+
{ id: "config3", name: "Config 3" },
189+
{ id: "config4", name: "Config 4" },
190+
{ id: "config5", name: "Config 5" },
191+
{ id: "config6", name: "Config 6" },
192+
{ id: "config7", name: "Config 7" },
193+
],
194+
}
195+
render(<ApiConfigSelector {...props} />)
148196

149197
const trigger = screen.getByTestId("dropdown-trigger")
150198
fireEvent.click(trigger)
@@ -158,7 +206,19 @@ describe("ApiConfigSelector", () => {
158206
})
159207

160208
test("clears search when X button is clicked", async () => {
161-
render(<ApiConfigSelector {...defaultProps} />)
209+
const props = {
210+
...defaultProps,
211+
listApiConfigMeta: [
212+
{ id: "config1", name: "Config 1" },
213+
{ id: "config2", name: "Config 2" },
214+
{ id: "config3", name: "Config 3" },
215+
{ id: "config4", name: "Config 4" },
216+
{ id: "config5", name: "Config 5" },
217+
{ id: "config6", name: "Config 6" },
218+
{ id: "config7", name: "Config 7" },
219+
],
220+
}
221+
render(<ApiConfigSelector {...props} />)
162222

163223
const trigger = screen.getByTestId("dropdown-trigger")
164224
fireEvent.click(trigger)
@@ -267,8 +327,20 @@ describe("ApiConfigSelector", () => {
267327
})
268328
})
269329

270-
test("renders bottom bar with title and info icon", () => {
271-
render(<ApiConfigSelector {...defaultProps} />)
330+
test("renders bottom bar with title and info icon when more than 6 configs", () => {
331+
const props = {
332+
...defaultProps,
333+
listApiConfigMeta: [
334+
{ id: "config1", name: "Config 1" },
335+
{ id: "config2", name: "Config 2" },
336+
{ id: "config3", name: "Config 3" },
337+
{ id: "config4", name: "Config 4" },
338+
{ id: "config5", name: "Config 5" },
339+
{ id: "config6", name: "Config 6" },
340+
{ id: "config7", name: "Config 7" },
341+
],
342+
}
343+
render(<ApiConfigSelector {...props} />)
272344

273345
const trigger = screen.getByTestId("dropdown-trigger")
274346
fireEvent.click(trigger)
@@ -281,6 +353,20 @@ describe("ApiConfigSelector", () => {
281353
expect(infoIcon).toBeInTheDocument()
282354
})
283355

356+
test("renders bottom bar with title but no info icon when 6 or fewer configs", () => {
357+
render(<ApiConfigSelector {...defaultProps} />)
358+
359+
const trigger = screen.getByTestId("dropdown-trigger")
360+
fireEvent.click(trigger)
361+
362+
// Check for the title
363+
expect(screen.getByText("prompts:apiConfiguration.title")).toBeInTheDocument()
364+
365+
// Check that info icon is not present
366+
const infoIcon = screen.getByTestId("popover-content").querySelector(".codicon-info")
367+
expect(infoIcon).not.toBeInTheDocument()
368+
})
369+
284370
test("handles empty config list gracefully", () => {
285371
const props = {
286372
...defaultProps,
@@ -292,13 +378,26 @@ describe("ApiConfigSelector", () => {
292378
const trigger = screen.getByTestId("dropdown-trigger")
293379
fireEvent.click(trigger)
294380

295-
// Should still render the search and bottom bar
296-
expect(screen.getByPlaceholderText("common:ui.search_placeholder")).toBeInTheDocument()
381+
// Should render info blurb instead of search for empty list
382+
expect(screen.queryByPlaceholderText("common:ui.search_placeholder")).not.toBeInTheDocument()
383+
expect(screen.getByText("prompts:apiConfiguration.select")).toBeInTheDocument()
297384
expect(screen.getByText("prompts:apiConfiguration.title")).toBeInTheDocument()
298385
})
299386

300387
test("maintains search value when pinning/unpinning", async () => {
301-
render(<ApiConfigSelector {...defaultProps} />)
388+
const props = {
389+
...defaultProps,
390+
listApiConfigMeta: [
391+
{ id: "config1", name: "Config 1" },
392+
{ id: "config2", name: "Config 2" },
393+
{ id: "config3", name: "Config 3" },
394+
{ id: "config4", name: "Config 4" },
395+
{ id: "config5", name: "Config 5" },
396+
{ id: "config6", name: "Config 6" },
397+
{ id: "config7", name: "Config 7" },
398+
],
399+
}
400+
render(<ApiConfigSelector {...props} />)
302401

303402
const trigger = screen.getByTestId("dropdown-trigger")
304403
fireEvent.click(trigger)

0 commit comments

Comments
 (0)