Skip to content

Commit a9dfaea

Browse files
committed
feat: Move search score threshold to collapsible advanced config section
- Move search score threshold setting to advanced configuration section - Make advanced section collapsible with toggle button (collapsed by default) - Position advanced section after action buttons for better UX flow - Add similarity score display badges in search results (3-decimal precision) - Include smooth CSS transitions and proper accessibility (aria-expanded, aria-controls) - Update all locale files with 'Advanced Configuration' translation - Update tests to handle collapsible behavior with comprehensive coverage Addresses UX feedback from mrubens on PR #5041 to de-emphasize complex settings for general users while keeping them accessible for advanced users. # Conflicts: # webview-ui/src/components/chat/CodebaseSearchResult.tsx
1 parent c399314 commit a9dfaea

File tree

21 files changed

+146
-53
lines changed

21 files changed

+146
-53
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const CodebaseSearchResult: React.FC<CodebaseSearchResultProps> = ({ filePath, s
2424
}
2525

2626
return (
27-
<StandardTooltip content={`Score: ${score.toFixed(2)}`}>
27+
<StandardTooltip content={`Similarity score: ${score.toFixed(3)} (click to open file)`}>
2828
<div
2929
onClick={handleClick}
3030
className="mb-1 p-2 border border-primary rounded cursor-pointer hover:bg-secondary hover:text-white">
@@ -35,6 +35,9 @@ const CodebaseSearchResult: React.FC<CodebaseSearchResultProps> = ({ filePath, s
3535
<span className="text-gray-500 truncate min-w-0 flex-1">
3636
{filePath.split("/").slice(0, -1).join("/")}
3737
</span>
38+
<span className="text-xs text-vscode-descriptionForeground bg-vscode-badge-background px-2 py-1 rounded whitespace-nowrap ml-auto">
39+
{score.toFixed(3)}
40+
</span>
3841
</div>
3942
</div>
4043
</StandardTooltip>

webview-ui/src/components/settings/CodeIndexSettings.tsx

Lines changed: 82 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export const CodeIndexSettings: React.FC<CodeIndexSettingsProps> = ({
6565
totalItems: 0,
6666
currentItemUnit: "items",
6767
})
68+
const [advancedExpanded, setAdvancedExpanded] = useState(false)
6869

6970
// Safely calculate available models for current provider
7071
const currentProvider = codebaseIndexConfig?.codebaseIndexEmbedderProvider
@@ -246,54 +247,6 @@ export const CodeIndexSettings: React.FC<CodeIndexSettingsProps> = ({
246247
</div>
247248
)}
248249

249-
<div>
250-
<span className="block font-medium mb-1">{t("settings:codeIndex.searchMinScoreLabel")}</span>
251-
<div className="flex items-center gap-2">
252-
<Slider
253-
min={0}
254-
max={1}
255-
step={0.05}
256-
value={[codebaseIndexConfig.codebaseIndexSearchMinScore ?? SEARCH_MIN_SCORE]}
257-
onValueChange={([value]) =>
258-
setCachedStateField("codebaseIndexConfig", {
259-
...codebaseIndexConfig,
260-
codebaseIndexSearchMinScore: value,
261-
})
262-
}
263-
data-testid="search-min-score-slider"
264-
aria-label={t("settings:codeIndex.searchMinScoreLabel")}
265-
/>
266-
<span className="w-10">
267-
{(codebaseIndexConfig.codebaseIndexSearchMinScore ?? SEARCH_MIN_SCORE).toFixed(2)}
268-
</span>
269-
<TooltipProvider>
270-
<Tooltip>
271-
<TooltipTrigger asChild>
272-
<Button
273-
variant="ghost"
274-
size="sm"
275-
onClick={() =>
276-
setCachedStateField("codebaseIndexConfig", {
277-
...codebaseIndexConfig,
278-
codebaseIndexSearchMinScore: SEARCH_MIN_SCORE,
279-
})
280-
}
281-
className="h-8 w-8 p-0"
282-
data-testid="search-min-score-reset-button">
283-
<span className="codicon codicon-debug-restart w-4 h-4" />
284-
</Button>
285-
</TooltipTrigger>
286-
<TooltipContent>
287-
<p>{t("settings:codeIndex.searchMinScoreResetTooltip")}</p>
288-
</TooltipContent>
289-
</Tooltip>
290-
</TooltipProvider>
291-
</div>
292-
<div className="text-vscode-descriptionForeground text-sm mt-1">
293-
{t("settings:codeIndex.searchMinScoreDescription")}
294-
</div>
295-
</div>
296-
297250
<div className="flex items-center gap-4 font-bold">
298251
<div>{t("settings:codeIndex.providerLabel")}</div>
299252
</div>
@@ -550,6 +503,87 @@ export const CodeIndexSettings: React.FC<CodeIndexSettingsProps> = ({
550503
</AlertDialog>
551504
)}
552505
</div>
506+
507+
{/* Advanced Configuration Section */}
508+
<div className="mt-6 pt-4 border-t border-vscode-widget-border">
509+
<button
510+
className="flex items-center justify-between w-full text-left group hover:bg-vscode-list-hoverBackground rounded p-2 -m-2"
511+
onClick={() => setAdvancedExpanded(!advancedExpanded)}
512+
aria-expanded={advancedExpanded}
513+
aria-controls="advanced-config-section">
514+
<div className="flex items-center gap-2 font-bold">
515+
<div>{t("settings:codeIndex.advancedConfigLabel")}</div>
516+
</div>
517+
<svg
518+
className={`w-4 h-4 text-vscode-foreground transition-transform duration-200 ${
519+
advancedExpanded ? "rotate-90" : ""
520+
}`}
521+
fill="none"
522+
stroke="currentColor"
523+
viewBox="0 0 24 24">
524+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
525+
</svg>
526+
</button>
527+
{advancedExpanded && (
528+
<div id="advanced-config-section" className="mt-4">
529+
<div className="flex flex-col gap-3">
530+
<div>
531+
<span className="block font-medium mb-1">
532+
{t("settings:codeIndex.searchMinScoreLabel")}
533+
</span>
534+
<div className="flex items-center gap-2">
535+
<Slider
536+
min={0}
537+
max={1}
538+
step={0.05}
539+
value={[
540+
codebaseIndexConfig.codebaseIndexSearchMinScore ?? SEARCH_MIN_SCORE,
541+
]}
542+
onValueChange={([value]) =>
543+
setCachedStateField("codebaseIndexConfig", {
544+
...codebaseIndexConfig,
545+
codebaseIndexSearchMinScore: value,
546+
})
547+
}
548+
data-testid="search-min-score-slider"
549+
aria-label={t("settings:codeIndex.searchMinScoreLabel")}
550+
/>
551+
<span className="w-10">
552+
{(
553+
codebaseIndexConfig.codebaseIndexSearchMinScore ?? SEARCH_MIN_SCORE
554+
).toFixed(2)}
555+
</span>
556+
<TooltipProvider>
557+
<Tooltip>
558+
<TooltipTrigger asChild>
559+
<Button
560+
variant="ghost"
561+
size="sm"
562+
onClick={() =>
563+
setCachedStateField("codebaseIndexConfig", {
564+
...codebaseIndexConfig,
565+
codebaseIndexSearchMinScore: SEARCH_MIN_SCORE,
566+
})
567+
}
568+
className="h-8 w-8 p-0"
569+
data-testid="search-min-score-reset-button">
570+
<span className="codicon codicon-debug-restart w-4 h-4" />
571+
</Button>
572+
</TooltipTrigger>
573+
<TooltipContent>
574+
<p>{t("settings:codeIndex.searchMinScoreResetTooltip")}</p>
575+
</TooltipContent>
576+
</Tooltip>
577+
</TooltipProvider>
578+
</div>
579+
<div className="text-vscode-descriptionForeground text-sm mt-1">
580+
{t("settings:codeIndex.searchMinScoreDescription")}
581+
</div>
582+
</div>
583+
</div>
584+
</div>
585+
)}
586+
</div>
553587
</div>
554588
)}
555589
</>

webview-ui/src/components/settings/__tests__/CodeIndexSettings.spec.tsx

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ vi.mock("@src/i18n/TranslationContext", () => ({
4747
"settings:codeIndex.searchMinScoreDescription":
4848
"Minimum similarity score (0.0-1.0) required for search results. Lower values return more results but may be less relevant. Higher values return fewer but more relevant results.",
4949
"settings:codeIndex.searchMinScoreResetTooltip": "Reset to default value (0.4)",
50+
"settings:codeIndex.advancedConfigLabel": "Advanced Configuration",
5051
}
5152
return translations[key] || key
5253
},
@@ -841,15 +842,29 @@ describe("CodeIndexSettings", () => {
841842
})
842843

843844
describe("Search Minimum Score Slider", () => {
844-
it("should render search minimum score slider with reset button", () => {
845+
const expandAdvancedConfig = () => {
846+
const advancedButton = screen.getByRole("button", { name: /Advanced Configuration/i })
847+
fireEvent.click(advancedButton)
848+
}
849+
850+
it("should render advanced configuration toggle button", () => {
845851
render(<CodeIndexSettings {...defaultProps} />)
846852

853+
expect(screen.getByRole("button", { name: /Advanced Configuration/i })).toBeInTheDocument()
854+
expect(screen.getByText("Advanced Configuration")).toBeInTheDocument()
855+
})
856+
857+
it("should render search minimum score slider with reset button when expanded", () => {
858+
render(<CodeIndexSettings {...defaultProps} />)
859+
860+
expandAdvancedConfig()
861+
847862
expect(screen.getByTestId("search-min-score-slider")).toBeInTheDocument()
848863
expect(screen.getByTestId("search-min-score-reset-button")).toBeInTheDocument()
849864
expect(screen.getByText("Search Score Threshold")).toBeInTheDocument()
850865
})
851866

852-
it("should display current search minimum score value", () => {
867+
it("should display current search minimum score value when expanded", () => {
853868
const propsWithScore = {
854869
...defaultProps,
855870
codebaseIndexConfig: {
@@ -860,12 +875,16 @@ describe("CodeIndexSettings", () => {
860875

861876
render(<CodeIndexSettings {...propsWithScore} />)
862877

878+
expandAdvancedConfig()
879+
863880
expect(screen.getByText("0.65")).toBeInTheDocument()
864881
})
865882

866883
it("should call setCachedStateField when slider value changes", () => {
867884
render(<CodeIndexSettings {...defaultProps} />)
868885

886+
expandAdvancedConfig()
887+
869888
const slider = screen.getByTestId("search-min-score-slider")
870889
fireEvent.change(slider, { target: { value: "0.8" } })
871890

@@ -886,6 +905,8 @@ describe("CodeIndexSettings", () => {
886905

887906
render(<CodeIndexSettings {...propsWithScore} />)
888907

908+
expandAdvancedConfig()
909+
889910
const resetButton = screen.getByTestId("search-min-score-reset-button")
890911
fireEvent.click(resetButton)
891912

@@ -906,8 +927,25 @@ describe("CodeIndexSettings", () => {
906927

907928
render(<CodeIndexSettings {...propsWithoutScore} />)
908929

930+
expandAdvancedConfig()
931+
909932
expect(screen.getByText("0.40")).toBeInTheDocument()
910933
})
934+
935+
it("should toggle advanced section visibility", () => {
936+
render(<CodeIndexSettings {...defaultProps} />)
937+
938+
// Initially collapsed - should not see slider
939+
expect(screen.queryByTestId("search-min-score-slider")).not.toBeInTheDocument()
940+
941+
// Expand advanced section
942+
expandAdvancedConfig()
943+
expect(screen.getByTestId("search-min-score-slider")).toBeInTheDocument()
944+
945+
// Collapse again
946+
expandAdvancedConfig()
947+
expect(screen.queryByTestId("search-min-score-slider")).not.toBeInTheDocument()
948+
})
911949
})
912950

913951
describe("Error Handling", () => {

webview-ui/src/i18n/locales/ca/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"ollamaUrlLabel": "URL d'Ollama:",
5757
"qdrantUrlLabel": "URL de Qdrant",
5858
"qdrantKeyLabel": "Clau de Qdrant:",
59+
"advancedConfigLabel": "Configuració avançada",
5960
"searchMinScoreLabel": "Llindar de puntuació de cerca",
6061
"searchMinScoreDescription": "Puntuació mínima de similitud (0.0-1.0) requerida per als resultats de la cerca. Valors més baixos retornen més resultats però poden ser menys rellevants. Valors més alts retornen menys resultats però més rellevants.",
6162
"searchMinScoreResetTooltip": "Restablir al valor per defecte (0.4)",

webview-ui/src/i18n/locales/de/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"ollamaUrlLabel": "Ollama-URL:",
5757
"qdrantUrlLabel": "Qdrant-URL",
5858
"qdrantKeyLabel": "Qdrant-Schlüssel:",
59+
"advancedConfigLabel": "Erweiterte Konfiguration",
5960
"searchMinScoreLabel": "Suchergebnis-Schwellenwert",
6061
"searchMinScoreDescription": "Mindestähnlichkeitswert (0.0-1.0), der für Suchergebnisse erforderlich ist. Niedrigere Werte liefern mehr Ergebnisse, die jedoch möglicherweise weniger relevant sind. Höhere Werte liefern weniger, aber relevantere Ergebnisse.",
6162
"searchMinScoreResetTooltip": "Auf Standardwert zurücksetzen (0.4)",

webview-ui/src/i18n/locales/en/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"ollamaUrlLabel": "Ollama URL:",
5757
"qdrantUrlLabel": "Qdrant URL",
5858
"qdrantKeyLabel": "Qdrant Key:",
59+
"advancedConfigLabel": "Advanced Configuration",
5960
"searchMinScoreLabel": "Search Score Threshold",
6061
"searchMinScoreDescription": "Minimum similarity score (0.0-1.0) required for search results. Lower values return more results but may be less relevant. Higher values return fewer but more relevant results.",
6162
"searchMinScoreResetTooltip": "Reset to default value (0.4)",

webview-ui/src/i18n/locales/es/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@
5656
"ollamaUrlLabel": "URL de Ollama:",
5757
"qdrantUrlLabel": "URL de Qdrant",
5858
"qdrantKeyLabel": "Clave de Qdrant:",
59+
"advancedConfigLabel": "Configuración avanzada",
5960
"searchMinScoreLabel": "Umbral de puntuación de búsqueda",
60-
"searchMinScoreDescription": "Puntuación mínima de similitud (0.0-1.0) requerida para los resultados de búsqueda. Valores más bajos devuelven más resultados pero pueden ser menos relevantes. Valores más altos devuelven menos resultados pero más relevantes.",
61+
"searchMinScoreDescription": "Puntuación mínima de similitud (0.0-1.0) requerida para los resultados de búsqueda. Valores más bajos devuelven más resultados pero могут ser menos relevantes. Valores más altos devuelven menos resultados pero más relevantes.",
6162
"searchMinScoreResetTooltip": "Restablecer al valor predeterminado (0.4)",
6263
"startIndexingButton": "Iniciar indexación",
6364
"clearIndexDataButton": "Borrar datos de índice",

webview-ui/src/i18n/locales/fr/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"ollamaUrlLabel": "URL Ollama :",
5757
"qdrantUrlLabel": "URL Qdrant",
5858
"qdrantKeyLabel": "Clé Qdrant :",
59+
"advancedConfigLabel": "Configuration avancée",
5960
"searchMinScoreLabel": "Seuil de score de recherche",
6061
"searchMinScoreDescription": "Score de similarité minimum (0.0-1.0) requis pour les résultats de recherche. Des valeurs plus faibles renvoient plus de résultats mais peuvent être moins pertinents. Des valeurs plus élevées renvoient moins de résultats mais plus pertinents.",
6162
"searchMinScoreResetTooltip": "Réinitialiser à la valeur par défaut (0.4)",

webview-ui/src/i18n/locales/hi/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"ollamaUrlLabel": "Ollama URL:",
5757
"qdrantUrlLabel": "Qdrant URL",
5858
"qdrantKeyLabel": "Qdrant कुंजी:",
59+
"advancedConfigLabel": "उन्नत कॉन्फ़िगरेशन",
5960
"searchMinScoreLabel": "खोज स्कोर थ्रेसहोल्ड",
6061
"searchMinScoreDescription": "खोज परिणामों के लिए आवश्यक न्यूनतम समानता स्कोर (0.0-1.0)। कम मान अधिक परिणाम लौटाते हैं लेकिन कम प्रासंगिक हो सकते हैं। उच्च मान कम लेकिन अधिक प्रासंगिक परिणाम लौटाते हैं।",
6162
"searchMinScoreResetTooltip": "डिफ़ॉल्ट मान पर रीसेट करें (0.4)",

webview-ui/src/i18n/locales/id/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"ollamaUrlLabel": "Ollama URL:",
5757
"qdrantUrlLabel": "Qdrant URL",
5858
"qdrantKeyLabel": "Qdrant Key:",
59+
"advancedConfigLabel": "Konfigurasi Lanjutan",
5960
"searchMinScoreLabel": "Ambang Batas Skor Pencarian",
6061
"searchMinScoreDescription": "Skor kesamaan minimum (0.0-1.0) yang diperlukan untuk hasil pencarian. Nilai yang lebih rendah mengembalikan lebih banyak hasil tetapi mungkin kurang relevan. Nilai yang lebih tinggi mengembalikan lebih sedikit hasil tetapi lebih relevan.",
6162
"searchMinScoreResetTooltip": "Reset ke nilai default (0.4)",

0 commit comments

Comments
 (0)