diff --git a/src/services/code-index/__tests__/config-manager.spec.ts b/src/services/code-index/__tests__/config-manager.spec.ts index 641abfa306..a5eee4230f 100644 --- a/src/services/code-index/__tests__/config-manager.spec.ts +++ b/src/services/code-index/__tests__/config-manager.spec.ts @@ -343,6 +343,89 @@ describe("CodeIndexConfigManager", () => { expect(result.requiresRestart).toBe(true) }) + it("should detect restart requirement when feature is enabled", async () => { + // Create a fresh config manager to ensure clean state + const freshConfigManager = new CodeIndexConfigManager(mockContextProxy) + + // Initial state - disabled + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: false, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + codebaseIndexEmbedderModelId: "text-embedding-3-small", + }) + setupSecretMocks({ + codeIndexOpenAiKey: "test-key", + codeIndexQdrantApiKey: "test-key", + }) + + await freshConfigManager.loadConfiguration() + + // Enable the feature + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + codebaseIndexEmbedderModelId: "text-embedding-3-small", + }) + + const result = await freshConfigManager.loadConfiguration() + expect(result.requiresRestart).toBe(true) + }) + + it("should detect restart requirement when feature is disabled", async () => { + // Create a fresh config manager to ensure clean state + const freshConfigManager = new CodeIndexConfigManager(mockContextProxy) + + // Initial state - enabled + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: true, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + codebaseIndexEmbedderModelId: "text-embedding-3-small", + }) + setupSecretMocks({ + codeIndexOpenAiKey: "test-key", + codeIndexQdrantApiKey: "test-key", + }) + + await freshConfigManager.loadConfiguration() + + // Disable the feature + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: false, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + codebaseIndexEmbedderModelId: "text-embedding-3-small", + }) + + const result = await freshConfigManager.loadConfiguration() + expect(result.requiresRestart).toBe(true) + }) + + it("should not require restart when feature remains disabled", async () => { + // Initial state - disabled + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: false, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + codebaseIndexEmbedderModelId: "text-embedding-3-small", + }) + + await configManager.loadConfiguration() + + // Change other settings while keeping feature disabled + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: false, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + codebaseIndexEmbedderModelId: "text-embedding-3-large", // Changed model + }) + + const result = await configManager.loadConfiguration() + expect(result.requiresRestart).toBe(false) + }) + describe("simplified restart detection", () => { it("should detect restart requirement for API key changes", async () => { // Initial state @@ -1215,7 +1298,39 @@ describe("CodeIndexConfigManager", () => { }) }) - it("should return correct feature enabled state", () => { + it("should return correct feature enabled state when enabled", () => { + expect(configManager.isFeatureEnabled).toBe(true) + }) + + it("should return false when codebaseIndexEnabled is false", async () => { + mockContextProxy.getGlobalState.mockReturnValue({ + codebaseIndexEnabled: false, + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + codebaseIndexEmbedderModelId: "text-embedding-3-large", + }) + setupSecretMocks({ + codeIndexOpenAiKey: "test-openai-key", + codeIndexQdrantApiKey: "test-qdrant-key", + }) + + await configManager.loadConfiguration() + expect(configManager.isFeatureEnabled).toBe(false) + }) + + it("should return true when codebaseIndexEnabled is undefined (default)", async () => { + mockContextProxy.getGlobalState.mockReturnValue({ + // codebaseIndexEnabled is undefined, should default to true + codebaseIndexQdrantUrl: "http://qdrant.local", + codebaseIndexEmbedderProvider: "openai", + codebaseIndexEmbedderModelId: "text-embedding-3-large", + }) + setupSecretMocks({ + codeIndexOpenAiKey: "test-openai-key", + codeIndexQdrantApiKey: "test-qdrant-key", + }) + + await configManager.loadConfiguration() expect(configManager.isFeatureEnabled).toBe(true) }) diff --git a/src/services/code-index/config-manager.ts b/src/services/code-index/config-manager.ts index 245621a1bd..943981f4ff 100644 --- a/src/services/code-index/config-manager.ts +++ b/src/services/code-index/config-manager.ts @@ -21,6 +21,7 @@ export class CodeIndexConfigManager { private qdrantApiKey?: string private searchMinScore?: number private searchMaxResults?: number + private codebaseIndexEnabled?: boolean constructor(private readonly contextProxy: ContextProxy) { // Initialize with current configuration to avoid false restart triggers @@ -68,7 +69,7 @@ export class CodeIndexConfigManager { const geminiApiKey = this.contextProxy?.getSecret("codebaseIndexGeminiApiKey") ?? "" // Update instance variables with configuration - // Note: codebaseIndexEnabled is no longer used as the feature is always enabled + this.codebaseIndexEnabled = codebaseIndexEnabled this.qdrantUrl = codebaseIndexQdrantUrl this.qdrantApiKey = qdrantApiKey ?? "" this.searchMinScore = codebaseIndexSearchMinScore @@ -142,7 +143,7 @@ export class CodeIndexConfigManager { }> { // Capture the ACTUAL previous state before loading new configuration const previousConfigSnapshot: PreviousConfigSnapshot = { - enabled: true, // Feature is always enabled + enabled: this.isFeatureEnabled, configured: this.isConfigured(), embedderProvider: this.embedderProvider, modelId: this.modelId, @@ -243,8 +244,13 @@ export class CodeIndexConfigManager { const prevQdrantUrl = prev?.qdrantUrl ?? "" const prevQdrantApiKey = prev?.qdrantApiKey ?? "" - // 1. Transition from unconfigured to configured - // Since the feature is always enabled, we only check configuration status + // 1. Check for enable/disable transitions + const nowEnabled = this.isFeatureEnabled + if (prevEnabled !== nowEnabled) { + return true + } + + // 2. Transition from unconfigured to configured if (!prevConfigured && nowConfigured) { return true } @@ -255,7 +261,6 @@ export class CodeIndexConfigManager { } // 4. CRITICAL CHANGES - Always restart for these - // Since feature is always enabled, we always check for critical changes // Provider change if (prevProvider !== this.embedderProvider) { @@ -354,7 +359,7 @@ export class CodeIndexConfigManager { * Gets whether the code indexing feature is enabled */ public get isFeatureEnabled(): boolean { - return true + return this.codebaseIndexEnabled ?? true } /** diff --git a/webview-ui/src/components/chat/CodeIndexPopover.tsx b/webview-ui/src/components/chat/CodeIndexPopover.tsx index 1243b7efa2..4c5255425d 100644 --- a/webview-ui/src/components/chat/CodeIndexPopover.tsx +++ b/webview-ui/src/components/chat/CodeIndexPopover.tsx @@ -526,525 +526,573 @@ export const CodeIndexPopover: React.FC = ({ )} + {/* Enable/Disable Toggle Section */} +
+
+
+ +

+ {t("settings:codeIndex.enabledDescription")} +

+
+ +
+
+ {/* Setup Settings Disclosure */} -
- + {currentSettings.codebaseIndexEnabled && ( +
+ - {isSetupSettingsOpen && ( -
- {/* Embedder Provider Section */} -
- - -
+ {isSetupSettingsOpen && ( +
+ {/* Embedder Provider Section */} +
+ + +
- {/* Provider-specific settings */} - {currentSettings.codebaseIndexEmbedderProvider === "openai" && ( - <> -
- - - updateSetting("codeIndexOpenAiKey", e.target.value) - } - placeholder={t("settings:codeIndex.openAiKeyPlaceholder")} - className={cn("w-full", { - "border-red-500": formErrors.codeIndexOpenAiKey, - })} - /> - {formErrors.codeIndexOpenAiKey && ( -

- {formErrors.codeIndexOpenAiKey} -

- )} -
+ {/* Provider-specific settings */} + {currentSettings.codebaseIndexEmbedderProvider === "openai" && ( + <> +
+ + + updateSetting("codeIndexOpenAiKey", e.target.value) + } + placeholder={t("settings:codeIndex.openAiKeyPlaceholder")} + className={cn("w-full", { + "border-red-500": formErrors.codeIndexOpenAiKey, + })} + /> + {formErrors.codeIndexOpenAiKey && ( +

+ {formErrors.codeIndexOpenAiKey} +

+ )} +
-
- - - updateSetting("codebaseIndexEmbedderModelId", e.target.value) - } - className={cn("w-full", { - "border-red-500": formErrors.codebaseIndexEmbedderModelId, - })}> - - {t("settings:codeIndex.selectModel")} - - {getAvailableModels().map((modelId) => { - const model = - codebaseIndexModels?.[ - currentSettings.codebaseIndexEmbedderProvider - ]?.[modelId] - return ( - - {modelId}{" "} - {model - ? t("settings:codeIndex.modelDimensions", { - dimension: model.dimension, - }) - : ""} - - ) - })} - - {formErrors.codebaseIndexEmbedderModelId && ( -

- {formErrors.codebaseIndexEmbedderModelId} -

- )} -
- - )} - - {currentSettings.codebaseIndexEmbedderProvider === "ollama" && ( - <> -
- - - updateSetting("codebaseIndexEmbedderBaseUrl", e.target.value) - } - onBlur={(e: any) => { - // Set default Ollama URL if field is empty - if (!e.target.value.trim()) { - e.target.value = DEFAULT_OLLAMA_URL +
+ + updateSetting( - "codebaseIndexEmbedderBaseUrl", - DEFAULT_OLLAMA_URL, + "codebaseIndexEmbedderModelId", + e.target.value, ) } - }} - placeholder={t("settings:codeIndex.ollamaUrlPlaceholder")} - className={cn("w-full", { - "border-red-500": formErrors.codebaseIndexEmbedderBaseUrl, - })} - /> - {formErrors.codebaseIndexEmbedderBaseUrl && ( -

- {formErrors.codebaseIndexEmbedderBaseUrl} -

- )} -
- -
- - - updateSetting("codebaseIndexEmbedderModelId", e.target.value) - } - className={cn("w-full", { - "border-red-500": formErrors.codebaseIndexEmbedderModelId, - })}> - - {t("settings:codeIndex.selectModel")} - - {getAvailableModels().map((modelId) => { - const model = - codebaseIndexModels?.[ - currentSettings.codebaseIndexEmbedderProvider - ]?.[modelId] - return ( - - {modelId}{" "} - {model - ? t("settings:codeIndex.modelDimensions", { - dimension: model.dimension, - }) - : ""} - - ) - })} - - {formErrors.codebaseIndexEmbedderModelId && ( -

- {formErrors.codebaseIndexEmbedderModelId} -

- )} -
- - )} - - {currentSettings.codebaseIndexEmbedderProvider === "openai-compatible" && ( - <> -
- - - updateSetting( - "codebaseIndexOpenAiCompatibleBaseUrl", - e.target.value, - ) - } - placeholder={t( - "settings:codeIndex.openAiCompatibleBaseUrlPlaceholder", + className={cn("w-full", { + "border-red-500": formErrors.codebaseIndexEmbedderModelId, + })}> + + {t("settings:codeIndex.selectModel")} + + {getAvailableModels().map((modelId) => { + const model = + codebaseIndexModels?.[ + currentSettings.codebaseIndexEmbedderProvider + ]?.[modelId] + return ( + + {modelId}{" "} + {model + ? t("settings:codeIndex.modelDimensions", { + dimension: model.dimension, + }) + : ""} + + ) + })} + + {formErrors.codebaseIndexEmbedderModelId && ( +

+ {formErrors.codebaseIndexEmbedderModelId} +

)} - className={cn("w-full", { - "border-red-500": - formErrors.codebaseIndexOpenAiCompatibleBaseUrl, - })} - /> - {formErrors.codebaseIndexOpenAiCompatibleBaseUrl && ( -

- {formErrors.codebaseIndexOpenAiCompatibleBaseUrl} -

- )} -
+
+ + )} -
- - - updateSetting( - "codebaseIndexOpenAiCompatibleApiKey", - e.target.value, - ) - } - placeholder={t( - "settings:codeIndex.openAiCompatibleApiKeyPlaceholder", + {currentSettings.codebaseIndexEmbedderProvider === "ollama" && ( + <> +
+ + + updateSetting( + "codebaseIndexEmbedderBaseUrl", + e.target.value, + ) + } + onBlur={(e: any) => { + // Set default Ollama URL if field is empty + if (!e.target.value.trim()) { + e.target.value = DEFAULT_OLLAMA_URL + updateSetting( + "codebaseIndexEmbedderBaseUrl", + DEFAULT_OLLAMA_URL, + ) + } + }} + placeholder={t("settings:codeIndex.ollamaUrlPlaceholder")} + className={cn("w-full", { + "border-red-500": formErrors.codebaseIndexEmbedderBaseUrl, + })} + /> + {formErrors.codebaseIndexEmbedderBaseUrl && ( +

+ {formErrors.codebaseIndexEmbedderBaseUrl} +

)} - className={cn("w-full", { - "border-red-500": - formErrors.codebaseIndexOpenAiCompatibleApiKey, - })} - /> - {formErrors.codebaseIndexOpenAiCompatibleApiKey && ( -

- {formErrors.codebaseIndexOpenAiCompatibleApiKey} -

- )} -
+
-
- - - updateSetting("codebaseIndexEmbedderModelId", e.target.value) - } - placeholder={t("settings:codeIndex.modelPlaceholder")} - className={cn("w-full", { - "border-red-500": formErrors.codebaseIndexEmbedderModelId, - })} - /> - {formErrors.codebaseIndexEmbedderModelId && ( -

- {formErrors.codebaseIndexEmbedderModelId} -

- )} -
+
+ + + updateSetting( + "codebaseIndexEmbedderModelId", + e.target.value, + ) + } + className={cn("w-full", { + "border-red-500": formErrors.codebaseIndexEmbedderModelId, + })}> + + {t("settings:codeIndex.selectModel")} + + {getAvailableModels().map((modelId) => { + const model = + codebaseIndexModels?.[ + currentSettings.codebaseIndexEmbedderProvider + ]?.[modelId] + return ( + + {modelId}{" "} + {model + ? t("settings:codeIndex.modelDimensions", { + dimension: model.dimension, + }) + : ""} + + ) + })} + + {formErrors.codebaseIndexEmbedderModelId && ( +

+ {formErrors.codebaseIndexEmbedderModelId} +

+ )} +
+ + )} -
- - { - const value = e.target.value - ? parseInt(e.target.value) - : undefined - updateSetting("codebaseIndexEmbedderModelDimension", value) - }} - placeholder={t("settings:codeIndex.modelDimensionPlaceholder")} - className={cn("w-full", { - "border-red-500": - formErrors.codebaseIndexEmbedderModelDimension, - })} - /> - {formErrors.codebaseIndexEmbedderModelDimension && ( -

- {formErrors.codebaseIndexEmbedderModelDimension} -

- )} -
- - )} + {currentSettings.codebaseIndexEmbedderProvider === "openai-compatible" && ( + <> +
+ + + updateSetting( + "codebaseIndexOpenAiCompatibleBaseUrl", + e.target.value, + ) + } + placeholder={t( + "settings:codeIndex.openAiCompatibleBaseUrlPlaceholder", + )} + className={cn("w-full", { + "border-red-500": + formErrors.codebaseIndexOpenAiCompatibleBaseUrl, + })} + /> + {formErrors.codebaseIndexOpenAiCompatibleBaseUrl && ( +

+ {formErrors.codebaseIndexOpenAiCompatibleBaseUrl} +

+ )} +
- {currentSettings.codebaseIndexEmbedderProvider === "gemini" && ( - <> -
- - - updateSetting("codebaseIndexGeminiApiKey", e.target.value) - } - placeholder={t("settings:codeIndex.geminiApiKeyPlaceholder")} - className={cn("w-full", { - "border-red-500": formErrors.codebaseIndexGeminiApiKey, - })} - /> - {formErrors.codebaseIndexGeminiApiKey && ( -

- {formErrors.codebaseIndexGeminiApiKey} -

- )} -
+
+ + + updateSetting( + "codebaseIndexOpenAiCompatibleApiKey", + e.target.value, + ) + } + placeholder={t( + "settings:codeIndex.openAiCompatibleApiKeyPlaceholder", + )} + className={cn("w-full", { + "border-red-500": + formErrors.codebaseIndexOpenAiCompatibleApiKey, + })} + /> + {formErrors.codebaseIndexOpenAiCompatibleApiKey && ( +

+ {formErrors.codebaseIndexOpenAiCompatibleApiKey} +

+ )} +
-
- - - updateSetting("codebaseIndexEmbedderModelId", e.target.value) - } - className={cn("w-full", { - "border-red-500": formErrors.codebaseIndexEmbedderModelId, - })}> - - {t("settings:codeIndex.selectModel")} - - {getAvailableModels().map((modelId) => { - const model = - codebaseIndexModels?.[ - currentSettings.codebaseIndexEmbedderProvider - ]?.[modelId] - return ( - - {modelId}{" "} - {model - ? t("settings:codeIndex.modelDimensions", { - dimension: model.dimension, - }) - : ""} - - ) - })} - - {formErrors.codebaseIndexEmbedderModelId && ( -

- {formErrors.codebaseIndexEmbedderModelId} -

- )} -
- - )} +
+ + + updateSetting( + "codebaseIndexEmbedderModelId", + e.target.value, + ) + } + placeholder={t("settings:codeIndex.modelPlaceholder")} + className={cn("w-full", { + "border-red-500": formErrors.codebaseIndexEmbedderModelId, + })} + /> + {formErrors.codebaseIndexEmbedderModelId && ( +

+ {formErrors.codebaseIndexEmbedderModelId} +

+ )} +
- {/* Qdrant Settings */} -
- - - updateSetting("codebaseIndexQdrantUrl", e.target.value) - } - onBlur={(e: any) => { - // Set default Qdrant URL if field is empty - if (!e.target.value.trim()) { - currentSettings.codebaseIndexQdrantUrl = DEFAULT_QDRANT_URL - updateSetting("codebaseIndexQdrantUrl", DEFAULT_QDRANT_URL) +
+ + { + const value = e.target.value + ? parseInt(e.target.value) + : undefined + updateSetting("codebaseIndexEmbedderModelDimension", value) + }} + placeholder={t("settings:codeIndex.modelDimensionPlaceholder")} + className={cn("w-full", { + "border-red-500": + formErrors.codebaseIndexEmbedderModelDimension, + })} + /> + {formErrors.codebaseIndexEmbedderModelDimension && ( +

+ {formErrors.codebaseIndexEmbedderModelDimension} +

+ )} +
+ + )} + + {currentSettings.codebaseIndexEmbedderProvider === "gemini" && ( + <> +
+ + + updateSetting("codebaseIndexGeminiApiKey", e.target.value) + } + placeholder={t("settings:codeIndex.geminiApiKeyPlaceholder")} + className={cn("w-full", { + "border-red-500": formErrors.codebaseIndexGeminiApiKey, + })} + /> + {formErrors.codebaseIndexGeminiApiKey && ( +

+ {formErrors.codebaseIndexGeminiApiKey} +

+ )} +
+ +
+ + + updateSetting( + "codebaseIndexEmbedderModelId", + e.target.value, + ) + } + className={cn("w-full", { + "border-red-500": formErrors.codebaseIndexEmbedderModelId, + })}> + + {t("settings:codeIndex.selectModel")} + + {getAvailableModels().map((modelId) => { + const model = + codebaseIndexModels?.[ + currentSettings.codebaseIndexEmbedderProvider + ]?.[modelId] + return ( + + {modelId}{" "} + {model + ? t("settings:codeIndex.modelDimensions", { + dimension: model.dimension, + }) + : ""} + + ) + })} + + {formErrors.codebaseIndexEmbedderModelId && ( +

+ {formErrors.codebaseIndexEmbedderModelId} +

+ )} +
+ + )} + + {/* Qdrant Settings */} +
+ + + updateSetting("codebaseIndexQdrantUrl", e.target.value) } - }} - placeholder={t("settings:codeIndex.qdrantUrlPlaceholder")} - className={cn("w-full", { - "border-red-500": formErrors.codebaseIndexQdrantUrl, - })} - /> - {formErrors.codebaseIndexQdrantUrl && ( -

- {formErrors.codebaseIndexQdrantUrl} -

- )} -
+ onBlur={(e: any) => { + // Set default Qdrant URL if field is empty + if (!e.target.value.trim()) { + currentSettings.codebaseIndexQdrantUrl = DEFAULT_QDRANT_URL + updateSetting("codebaseIndexQdrantUrl", DEFAULT_QDRANT_URL) + } + }} + placeholder={t("settings:codeIndex.qdrantUrlPlaceholder")} + className={cn("w-full", { + "border-red-500": formErrors.codebaseIndexQdrantUrl, + })} + /> + {formErrors.codebaseIndexQdrantUrl && ( +

+ {formErrors.codebaseIndexQdrantUrl} +

+ )} +
-
- - updateSetting("codeIndexQdrantApiKey", e.target.value)} - placeholder={t("settings:codeIndex.qdrantApiKeyPlaceholder")} - className={cn("w-full", { - "border-red-500": formErrors.codeIndexQdrantApiKey, - })} - /> - {formErrors.codeIndexQdrantApiKey && ( -

- {formErrors.codeIndexQdrantApiKey} -

- )} +
+ + + updateSetting("codeIndexQdrantApiKey", e.target.value) + } + placeholder={t("settings:codeIndex.qdrantApiKeyPlaceholder")} + className={cn("w-full", { + "border-red-500": formErrors.codeIndexQdrantApiKey, + })} + /> + {formErrors.codeIndexQdrantApiKey && ( +

+ {formErrors.codeIndexQdrantApiKey} +

+ )} +
-
- )} -
+ )} +
+ )} {/* Advanced Settings Disclosure */} -
- + {currentSettings.codebaseIndexEnabled && ( +
+ - {isAdvancedSettingsOpen && ( -
- {/* Search Score Threshold Slider */} -
-
- - - - + {isAdvancedSettingsOpen && ( +
+ {/* Search Score Threshold Slider */} +
+
+ + + + +
+
+ + updateSetting("codebaseIndexSearchMinScore", values[0]) + } + className="flex-1" + data-testid="search-min-score-slider" + /> + + {( + currentSettings.codebaseIndexSearchMinScore ?? + CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE + ).toFixed(2)} + + + updateSetting( + "codebaseIndexSearchMinScore", + CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE, + ) + }> + + +
-
- - updateSetting("codebaseIndexSearchMinScore", values[0]) - } - className="flex-1" - data-testid="search-min-score-slider" - /> - - {( - currentSettings.codebaseIndexSearchMinScore ?? - CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE - ).toFixed(2)} - - - updateSetting( - "codebaseIndexSearchMinScore", - CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE, - ) - }> - - + + {/* Maximum Search Results Slider */} +
+
+ + + + +
+
+ + updateSetting("codebaseIndexSearchMaxResults", values[0]) + } + className="flex-1" + data-testid="search-max-results-slider" + /> + + {currentSettings.codebaseIndexSearchMaxResults ?? + CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS} + + + updateSetting( + "codebaseIndexSearchMaxResults", + CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS, + ) + }> + + +
- - {/* Maximum Search Results Slider */} -
-
- - - - -
-
- - updateSetting("codebaseIndexSearchMaxResults", values[0]) - } - className="flex-1" - data-testid="search-max-results-slider" - /> - - {currentSettings.codebaseIndexSearchMaxResults ?? - CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS} - - - updateSetting( - "codebaseIndexSearchMaxResults", - CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS, - ) - }> - - -
-
-
- )} -
+ )} +
+ )} {/* Action Buttons */}
diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 4cc530403a..89720a0509 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -40,6 +40,8 @@ "title": "Codebase Indexing", "description": "Configure codebase indexing settings to enable semantic search of your project. <0>Learn more", "statusTitle": "Status", + "enabledLabel": "Enable Codebase Indexing", + "enabledDescription": "Toggle codebase indexing on or off. When disabled, the codebase_search tool will not be available.", "enableLabel": "Enable Codebase Indexing", "enableDescription": "<0>Codebase Indexing is an experimental feature that creates a semantic search index of your project using AI embeddings. This enables Roo Code to better understand and navigate large codebases by finding relevant code based on meaning rather than just keywords.", "settingsTitle": "Indexing Settings",