- {/* Provider-specific settings */}
- {currentSettings.codebaseIndexEmbedderProvider === "openai" && (
- <>
-
+ {/* Advanced Settings Disclosure */}
+
+
+
+ {isAdvancedSettingsOpen && (
+
+ {/* Search Score Threshold Slider */}
+
+
-
- updateSetting("codeIndexOpenAiKey", e.target.value)
+
+
+
+
+
+
+ updateSetting("codebaseIndexSearchMinScore", values[0])
}
- placeholder={t("settings:codeIndex.openAiKeyPlaceholder")}
- className="w-full"
+ className="flex-1"
+ data-testid="search-min-score-slider"
/>
-
-
-
-
-
- updateSetting("codebaseIndexEmbedderModelId", e.target.value)
- }
- className="w-full">
-
- {t("settings:codeIndex.selectModel")}
-
- {getAvailableModels().map((modelId) => {
- const model =
- codebaseIndexModels?.[
- currentSettings.codebaseIndexEmbedderProvider
- ]?.[modelId]
- return (
-
- {modelId}{" "}
- {model
- ? t("settings:codeIndex.modelDimensions", {
- dimension: model.dimension,
- })
- : ""}
-
- )
- })}
-
-
- >
- )}
-
- {currentSettings.codebaseIndexEmbedderProvider === "ollama" && (
- <>
-
-
-
- updateSetting("codebaseIndexEmbedderBaseUrl", e.target.value)
- }
- placeholder={t("settings:codeIndex.ollamaUrlPlaceholder")}
- className="w-full"
- />
-
-
-
-
-
- updateSetting("codebaseIndexEmbedderModelId", e.target.value)
- }
- className="w-full">
-
- {t("settings:codeIndex.selectModel")}
-
- {getAvailableModels().map((modelId) => {
- const model =
- codebaseIndexModels?.[
- currentSettings.codebaseIndexEmbedderProvider
- ]?.[modelId]
- return (
-
- {modelId}{" "}
- {model
- ? t("settings:codeIndex.modelDimensions", {
- dimension: model.dimension,
- })
- : ""}
-
- )
- })}
-
-
- >
- )}
-
- {currentSettings.codebaseIndexEmbedderProvider === "openai-compatible" && (
- <>
-
-
-
+
+ {(
+ currentSettings.codebaseIndexSearchMinScore ??
+ CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE
+ ).toFixed(2)}
+
+
updateSetting(
- "codebaseIndexOpenAiCompatibleBaseUrl",
- e.target.value,
+ "codebaseIndexSearchMinScore",
+ CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE,
)
- }
- placeholder={t("settings:codeIndex.openAiCompatibleBaseUrlPlaceholder")}
- className="w-full"
- />
+ }>
+
+
+
-
+ {/* Maximum Search Results Slider */}
+
+
-
- updateSetting("codebaseIndexOpenAiCompatibleApiKey", e.target.value)
- }
- placeholder={t("settings:codeIndex.openAiCompatibleApiKeyPlaceholder")}
- className="w-full"
- />
+
+
+
-
-
-
-
- updateSetting("codebaseIndexEmbedderModelId", e.target.value)
+
+
+ updateSetting("codebaseIndexSearchMaxResults", values[0])
}
- placeholder={t("settings:codeIndex.modelPlaceholder")}
- className="w-full"
+ className="flex-1"
+ data-testid="search-max-results-slider"
/>
-
-
-
-
- {
- const value = e.target.value ? parseInt(e.target.value) : undefined
- updateSetting("codebaseIndexEmbedderModelDimension", value)
- }}
- placeholder={t("settings:codeIndex.modelDimensionPlaceholder")}
- className="w-full"
- />
-
- >
- )}
-
- {currentSettings.codebaseIndexEmbedderProvider === "gemini" && (
- <>
-
-
-
- updateSetting("codebaseIndexGeminiApiKey", e.target.value)
- }
- placeholder={t("settings:codeIndex.geminiApiKeyPlaceholder")}
- className="w-full"
- />
-
-
-
-
-
- updateSetting("codebaseIndexEmbedderModelId", e.target.value)
- }
- className="w-full">
-
- {t("settings:codeIndex.selectModel")}
-
- {getAvailableModels().map((modelId) => {
- const model =
- codebaseIndexModels?.[
- currentSettings.codebaseIndexEmbedderProvider
- ]?.[modelId]
- return (
-
- {modelId}{" "}
- {model
- ? t("settings:codeIndex.modelDimensions", {
- dimension: model.dimension,
- })
- : ""}
-
+
+ {currentSettings.codebaseIndexSearchMaxResults ??
+ CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS}
+
+
+ updateSetting(
+ "codebaseIndexSearchMaxResults",
+ CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS,
)
- })}
-
+ }>
+
+
- >
- )}
-
- {/* Qdrant Settings */}
-
-
- updateSetting("codebaseIndexQdrantUrl", e.target.value)}
- placeholder={t("settings:codeIndex.qdrantUrlPlaceholder")}
- className="w-full"
- />
-
-
-
-
- updateSetting("codeIndexQdrantApiKey", e.target.value)}
- placeholder={t("settings:codeIndex.qdrantApiKeyPlaceholder")}
- className="w-full"
- />
-
-
- )}
-
-
- {/* Advanced Settings Disclosure */}
-
-
-
- {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,
- )
- }>
-
-
-
- {/* 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 */}
-
-
- {(indexingStatus.systemStatus === "Error" || indexingStatus.systemStatus === "Standby") && (
-
vscode.postMessage({ type: "startIndexing" })}
- disabled={saveStatus === "saving" || hasUnsavedChanges}>
- {t("settings:codeIndex.startIndexingButton")}
-
- )}
-
- {(indexingStatus.systemStatus === "Indexed" || indexingStatus.systemStatus === "Error") && (
-
-
-
- {t("settings:codeIndex.clearIndexDataButton")}
-
-
-
-
-
- {t("settings:codeIndex.clearDataDialog.title")}
-
-
- {t("settings:codeIndex.clearDataDialog.description")}
-
-
-
-
- {t("settings:codeIndex.clearDataDialog.cancelButton")}
-
- vscode.postMessage({ type: "clearIndexData" })}>
- {t("settings:codeIndex.clearDataDialog.confirmButton")}
-
-
-
-
)}
-
- {saveStatus === "saving"
- ? t("settings:codeIndex.saving")
- : t("settings:codeIndex.saveSettings")}
-
-
+ {/* Action Buttons */}
+
+
+ {(indexingStatus.systemStatus === "Error" ||
+ indexingStatus.systemStatus === "Standby") && (
+
vscode.postMessage({ type: "startIndexing" })}
+ disabled={saveStatus === "saving" || hasUnsavedChanges}>
+ {t("settings:codeIndex.startIndexingButton")}
+
+ )}
- {/* Save Status Messages */}
- {saveStatus === "error" && (
-
-
- {saveError || t("settings:codeIndex.saveError")}
-
+ {(indexingStatus.systemStatus === "Indexed" ||
+ indexingStatus.systemStatus === "Error") && (
+
+
+
+ {t("settings:codeIndex.clearIndexDataButton")}
+
+
+
+
+
+ {t("settings:codeIndex.clearDataDialog.title")}
+
+
+ {t("settings:codeIndex.clearDataDialog.description")}
+
+
+
+
+ {t("settings:codeIndex.clearDataDialog.cancelButton")}
+
+ vscode.postMessage({ type: "clearIndexData" })}>
+ {t("settings:codeIndex.clearDataDialog.confirmButton")}
+
+
+
+
+ )}
+
+
+
+ {saveStatus === "saving"
+ ? t("settings:codeIndex.saving")
+ : t("settings:codeIndex.saveSettings")}
+
- )}
-
-
-
+
+ {/* Save Status Messages */}
+ {saveStatus === "error" && (
+
+
+ {saveError || t("settings:codeIndex.saveError")}
+
+
+ )}
+
+
+
+
+ {/* Discard Changes Dialog */}
+
+
+
+
+
+ {t("settings:unsavedChangesDialog.title")}
+
+
+ {t("settings:unsavedChangesDialog.description")}
+
+
+
+ onConfirmDialogResult(false)}>
+ {t("settings:unsavedChangesDialog.cancelButton")}
+
+ onConfirmDialogResult(true)}>
+ {t("settings:unsavedChangesDialog.discardButton")}
+
+
+
+
+ >
)
}
diff --git a/webview-ui/src/components/chat/FollowUpSuggest.tsx b/webview-ui/src/components/chat/FollowUpSuggest.tsx
index 5649da744a..1ffe31bbcb 100644
--- a/webview-ui/src/components/chat/FollowUpSuggest.tsx
+++ b/webview-ui/src/components/chat/FollowUpSuggest.tsx
@@ -14,10 +14,17 @@ interface FollowUpSuggestProps {
suggestions?: SuggestionItem[]
onSuggestionClick?: (suggestion: SuggestionItem, event?: React.MouseEvent) => void
ts: number
- onUnmount?: () => void
+ onCancelAutoApproval?: () => void
+ isAnswered?: boolean
}
-export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, onUnmount }: FollowUpSuggestProps) => {
+export const FollowUpSuggest = ({
+ suggestions = [],
+ onSuggestionClick,
+ ts = 1,
+ onCancelAutoApproval,
+ isAnswered = false,
+}: FollowUpSuggestProps) => {
const { autoApprovalEnabled, alwaysAllowFollowupQuestions, followupAutoApproveTimeoutMs } = useExtensionState()
const [countdown, setCountdown] = useState
(null)
const [suggestionSelected, setSuggestionSelected] = useState(false)
@@ -26,7 +33,14 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o
// Start countdown timer when auto-approval is enabled for follow-up questions
useEffect(() => {
// Only start countdown if auto-approval is enabled for follow-up questions and no suggestion has been selected
- if (autoApprovalEnabled && alwaysAllowFollowupQuestions && suggestions.length > 0 && !suggestionSelected) {
+ // Also stop countdown if the question has been answered
+ if (
+ autoApprovalEnabled &&
+ alwaysAllowFollowupQuestions &&
+ suggestions.length > 0 &&
+ !suggestionSelected &&
+ !isAnswered
+ ) {
// Start with the configured timeout in seconds
const timeoutMs =
typeof followupAutoApproveTimeoutMs === "number" && !isNaN(followupAutoApproveTimeoutMs)
@@ -52,7 +66,7 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o
clearInterval(intervalId)
// Notify parent component that this component is unmounting
// so it can clear any related timeouts
- onUnmount?.()
+ onCancelAutoApproval?.()
}
} else {
setCountdown(null)
@@ -63,7 +77,8 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o
suggestions,
followupAutoApproveTimeoutMs,
suggestionSelected,
- onUnmount,
+ onCancelAutoApproval,
+ isAnswered,
])
const handleSuggestionClick = useCallback(
(suggestion: SuggestionItem, event: React.MouseEvent) => {
@@ -72,14 +87,14 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o
setSuggestionSelected(true)
// Also notify parent component to cancel auto-approval timeout
// This prevents race conditions between visual countdown and actual timeout
- onUnmount?.()
+ onCancelAutoApproval?.()
}
// Pass the suggestion object to the parent component
// The parent component will handle mode switching if needed
onSuggestionClick?.(suggestion, event)
},
- [onSuggestionClick, onUnmount],
+ [onSuggestionClick, onCancelAutoApproval],
)
// Don't render if there are no suggestions or no click handler.
@@ -100,7 +115,7 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o
onClick={(event) => handleSuggestionClick(suggestion, event)}
aria-label={suggestion.answer}>
{suggestion.answer}
- {isFirstSuggestion && countdown !== null && !suggestionSelected && (
+ {isFirstSuggestion && countdown !== null && !suggestionSelected && !isAnswered && (
diff --git a/webview-ui/src/components/chat/__tests__/CodeIndexPopover.validation.spec.tsx b/webview-ui/src/components/chat/__tests__/CodeIndexPopover.validation.spec.tsx
new file mode 100644
index 0000000000..4dd89288ea
--- /dev/null
+++ b/webview-ui/src/components/chat/__tests__/CodeIndexPopover.validation.spec.tsx
@@ -0,0 +1,375 @@
+import React from "react"
+import { render, screen, fireEvent, waitFor } from "@testing-library/react"
+import { describe, it, expect, vi, beforeEach } from "vitest"
+import { CodeIndexPopover } from "../CodeIndexPopover"
+
+// Mock the vscode API
+vi.mock("@src/utils/vscode", () => ({
+ vscode: {
+ postMessage: vi.fn(),
+ },
+}))
+
+// Mock the extension state context
+vi.mock("@src/context/ExtensionStateContext", () => ({
+ useExtensionState: vi.fn(),
+}))
+
+// Mock the translation context
+vi.mock("@src/i18n/TranslationContext", () => ({
+ useAppTranslation: () => ({ t: vi.fn((key: string) => key) }),
+}))
+
+// Mock react-i18next
+vi.mock("react-i18next", () => ({
+ Trans: ({ children }: { children: React.ReactNode }) => {children}
,
+}))
+
+// Mock the doc links utility
+vi.mock("@src/utils/docLinks", () => ({
+ buildDocLink: vi.fn(() => "https://docs.roocode.com"),
+}))
+
+// Mock the portal hook
+vi.mock("@src/components/ui/hooks/useRooPortal", () => ({
+ useRooPortal: () => ({ portalContainer: document.body }),
+}))
+
+// Mock Radix UI components to avoid portal issues
+vi.mock("@src/components/ui", () => ({
+ Popover: ({ children }: { children: React.ReactNode }) => {children}
,
+ PopoverContent: ({ children }: { children: React.ReactNode }) => {children}
,
+ PopoverTrigger: ({ children }: { children: React.ReactNode }) => {children}
,
+ Select: ({ children }: { children: React.ReactNode }) => {children}
,
+ SelectContent: ({ children }: { children: React.ReactNode }) => {children}
,
+ SelectItem: ({ children, value }: { children: React.ReactNode; value: string }) => (
+
+ {children}
+
+ ),
+ SelectTrigger: ({ children }: { children: React.ReactNode }) => {children}
,
+ SelectValue: ({ placeholder }: { placeholder?: string }) => {placeholder},
+ AlertDialog: ({ children }: { children: React.ReactNode }) => {children}
,
+ AlertDialogAction: ({ children }: { children: React.ReactNode }) => ,
+ AlertDialogCancel: ({ children }: { children: React.ReactNode }) => ,
+ AlertDialogContent: ({ children }: { children: React.ReactNode }) => {children}
,
+ AlertDialogDescription: ({ children }: { children: React.ReactNode }) => {children}
,
+ AlertDialogFooter: ({ children }: { children: React.ReactNode }) => {children}
,
+ AlertDialogHeader: ({ children }: { children: React.ReactNode }) => {children}
,
+ AlertDialogTitle: ({ children }: { children: React.ReactNode }) => {children}
,
+ AlertDialogTrigger: ({ children }: { children: React.ReactNode }) => {children}
,
+ Slider: ({ value, onValueChange }: { value: number[]; onValueChange: (value: number[]) => void }) => (
+ onValueChange([parseInt(e.target.value)])} />
+ ),
+ StandardTooltip: ({ children }: { children: React.ReactNode }) => {children}
,
+ cn: (...classes: string[]) => classes.join(" "),
+}))
+
+// Mock VSCode web components to behave like regular HTML inputs
+vi.mock("@vscode/webview-ui-toolkit/react", () => ({
+ VSCodeTextField: ({ value, onInput, placeholder, className, ...rest }: any) => (
+ onInput && onInput(e)}
+ placeholder={placeholder}
+ className={className}
+ aria-label="Text field"
+ {...rest}
+ />
+ ),
+ VSCodeButton: ({ children, onClick, ...rest }: any) => (
+
+ ),
+ VSCodeDropdown: ({ value, onChange, children, className, ...rest }: any) => (
+
+ ),
+ VSCodeOption: ({ value, children, ...rest }: any) => (
+
+ ),
+ VSCodeLink: ({ href, children, ...rest }: any) => (
+
+ {children}
+
+ ),
+}))
+
+// Helper function to simulate input on form elements
+const simulateInput = (element: Element, value: string) => {
+ // Now that we're mocking VSCode components as regular HTML inputs,
+ // we can use standard fireEvent.change
+ fireEvent.change(element, { target: { value } })
+}
+
+describe("CodeIndexPopover Validation", () => {
+ let mockUseExtensionState: any
+
+ beforeEach(async () => {
+ vi.clearAllMocks()
+
+ // Get the mocked function
+ const { useExtensionState } = await import("@src/context/ExtensionStateContext")
+ mockUseExtensionState = vi.mocked(useExtensionState)
+
+ // Setup default extension state
+ mockUseExtensionState.mockReturnValue({
+ codebaseIndexConfig: {
+ codebaseIndexEnabled: false,
+ codebaseIndexQdrantUrl: "",
+ codebaseIndexEmbedderProvider: "openai",
+ codebaseIndexEmbedderBaseUrl: "",
+ codebaseIndexEmbedderModelId: "",
+ codebaseIndexSearchMaxResults: 10,
+ codebaseIndexSearchMinScore: 0.7,
+ codebaseIndexOpenAiCompatibleBaseUrl: "",
+ codebaseIndexEmbedderModelDimension: undefined,
+ },
+ codebaseIndexModels: {
+ openai: [{ dimension: 1536 }],
+ },
+ })
+ })
+
+ const renderComponent = () => {
+ return render(
+
+
+ ,
+ )
+ }
+
+ const openPopover = async () => {
+ const trigger = screen.getByText("Test Trigger")
+ fireEvent.click(trigger)
+
+ // Wait for popover to open
+ await waitFor(() => {
+ expect(screen.getByRole("dialog")).toBeInTheDocument()
+ })
+ }
+
+ const expandSetupSection = async () => {
+ const setupButton = screen.getByText("settings:codeIndex.setupConfigLabel")
+ fireEvent.click(setupButton)
+
+ // Wait for section to expand - look for vscode-text-field elements
+ await waitFor(() => {
+ const textFields = screen.getAllByLabelText("Text field")
+ expect(textFields.length).toBeGreaterThan(0)
+ })
+ }
+
+ describe("OpenAI Provider Validation", () => {
+ it("should show validation error when OpenAI API key is empty", async () => {
+ renderComponent()
+ await openPopover()
+ await expandSetupSection()
+
+ // First, make a change to enable the save button by modifying the Qdrant URL
+ const qdrantUrlField = screen.getByPlaceholderText(/settings:codeIndex.qdrantUrlPlaceholder/i)
+ fireEvent.change(qdrantUrlField, { target: { value: "http://localhost:6333" } })
+
+ // Wait for the save button to become enabled
+ await waitFor(() => {
+ const saveButton = screen.getByText("settings:codeIndex.saveSettings")
+ expect(saveButton).not.toBeDisabled()
+ })
+
+ // Now clear the OpenAI API key to create a validation error
+ const apiKeyField = screen.getByPlaceholderText(/settings:codeIndex.openAiKeyPlaceholder/i)
+ fireEvent.change(apiKeyField, { target: { value: "" } })
+
+ // Click the save button to trigger validation
+ const saveButton = screen.getByText("settings:codeIndex.saveSettings")
+ fireEvent.click(saveButton)
+
+ // Should show specific field error
+ await waitFor(() => {
+ expect(screen.getByText("settings:codeIndex.validation.openaiApiKeyRequired")).toBeInTheDocument()
+ })
+ })
+
+ it("should show validation error when model is not selected", async () => {
+ renderComponent()
+ await openPopover()
+ await expandSetupSection()
+
+ // First, make a change to enable the save button
+ const qdrantUrlField = screen.getByPlaceholderText(/settings:codeIndex.qdrantUrlPlaceholder/i)
+ fireEvent.change(qdrantUrlField, { target: { value: "http://localhost:6333" } })
+
+ // Set API key but leave model empty
+ const apiKeyField = screen.getByPlaceholderText(/settings:codeIndex.openAiKeyPlaceholder/i)
+ fireEvent.change(apiKeyField, { target: { value: "test-api-key" } })
+
+ // Wait for the save button to become enabled
+ await waitFor(() => {
+ const saveButton = screen.getByText("settings:codeIndex.saveSettings")
+ expect(saveButton).not.toBeDisabled()
+ })
+
+ const saveButton = screen.getByText("settings:codeIndex.saveSettings")
+ fireEvent.click(saveButton)
+
+ await waitFor(() => {
+ expect(screen.getByText("settings:codeIndex.validation.modelSelectionRequired")).toBeInTheDocument()
+ })
+ })
+ })
+
+ describe("Qdrant URL Validation", () => {
+ it("should show validation error when Qdrant URL is empty", async () => {
+ renderComponent()
+ await openPopover()
+ await expandSetupSection()
+
+ // First, make a change to enable the save button by setting API key
+ const apiKeyField = screen.getByPlaceholderText(/settings:codeIndex.openAiKeyPlaceholder/i)
+ fireEvent.change(apiKeyField, { target: { value: "test-api-key" } })
+
+ // Clear the Qdrant URL to create validation error
+ const qdrantUrlField = screen.getByPlaceholderText(/settings:codeIndex.qdrantUrlPlaceholder/i)
+ fireEvent.change(qdrantUrlField, { target: { value: "" } })
+
+ // Wait for the save button to become enabled
+ await waitFor(() => {
+ const saveButton = screen.getByText("settings:codeIndex.saveSettings")
+ expect(saveButton).not.toBeDisabled()
+ })
+
+ const saveButton = screen.getByText("settings:codeIndex.saveSettings")
+ fireEvent.click(saveButton)
+
+ await waitFor(() => {
+ expect(screen.getByText("settings:codeIndex.validation.invalidQdrantUrl")).toBeInTheDocument()
+ })
+ })
+
+ it("should show validation error when Qdrant URL is invalid", async () => {
+ renderComponent()
+ await openPopover()
+ await expandSetupSection()
+
+ // First, make a change to enable the save button by setting API key
+ const apiKeyField = screen.getByPlaceholderText(/settings:codeIndex.openAiKeyPlaceholder/i)
+ fireEvent.change(apiKeyField, { target: { value: "test-api-key" } })
+
+ // Set invalid Qdrant URL
+ const qdrantUrlField = screen.getByPlaceholderText(/settings:codeIndex.qdrantUrlPlaceholder/i)
+ fireEvent.change(qdrantUrlField, { target: { value: "invalid-url" } })
+
+ // Wait for the save button to become enabled
+ await waitFor(() => {
+ const saveButton = screen.getByText("settings:codeIndex.saveSettings")
+ expect(saveButton).not.toBeDisabled()
+ })
+
+ const saveButton = screen.getByText("settings:codeIndex.saveSettings")
+ fireEvent.click(saveButton)
+
+ await waitFor(() => {
+ expect(screen.getByText("settings:codeIndex.validation.invalidQdrantUrl")).toBeInTheDocument()
+ })
+ })
+ })
+
+ describe("Common Field Validation", () => {
+ it("should not show validation error for optional Qdrant API key", async () => {
+ renderComponent()
+ await openPopover()
+ await expandSetupSection()
+
+ // Set required fields to make form valid
+ const qdrantUrlField = screen.getByPlaceholderText(/settings:codeIndex.qdrantUrlPlaceholder/i)
+ fireEvent.change(qdrantUrlField, { target: { value: "http://localhost:6333" } })
+
+ const apiKeyField = screen.getByPlaceholderText(/settings:codeIndex.openAiKeyPlaceholder/i)
+ fireEvent.change(apiKeyField, { target: { value: "test-api-key" } })
+
+ // Select a model - this is required (get the select element specifically)
+ const modelSelect = screen.getAllByRole("combobox").find((el) => el.tagName === "SELECT")
+ if (modelSelect) {
+ fireEvent.change(modelSelect, { target: { value: "0" } })
+ }
+
+ // Leave Qdrant API key empty (it's optional)
+ const qdrantApiKeyField = screen.getByPlaceholderText(/settings:codeIndex.qdrantApiKeyPlaceholder/i)
+ fireEvent.change(qdrantApiKeyField, { target: { value: "" } })
+
+ // Wait for the save button to become enabled
+ await waitFor(() => {
+ const saveButton = screen.getByText("settings:codeIndex.saveSettings")
+ expect(saveButton).not.toBeDisabled()
+ })
+
+ const saveButton = screen.getByText("settings:codeIndex.saveSettings")
+ fireEvent.click(saveButton)
+
+ // Should not show validation errors since Qdrant API key is optional
+ })
+
+ it("should clear validation errors when fields are corrected", async () => {
+ renderComponent()
+ await openPopover()
+ await expandSetupSection()
+
+ // First make an invalid change to enable the save button and trigger validation
+ const textFields = screen.getAllByLabelText("Text field")
+ const qdrantField = textFields.find((field) =>
+ field.getAttribute("placeholder")?.toLowerCase().includes("qdrant"),
+ )
+
+ if (qdrantField) {
+ simulateInput(qdrantField, "invalid-url") // Invalid URL to trigger validation
+ }
+
+ // Wait for save button to be enabled
+ const saveButton = screen.getByText("settings:codeIndex.saveSettings")
+ await waitFor(() => {
+ expect(saveButton).not.toBeDisabled()
+ })
+
+ // Click save to trigger validation errors
+ fireEvent.click(saveButton)
+
+ // Now fix the errors with valid values
+ const apiKeyField = textFields.find(
+ (field) =>
+ field.getAttribute("placeholder")?.toLowerCase().includes("openai") ||
+ field.getAttribute("placeholder")?.toLowerCase().includes("key"),
+ )
+
+ // Set valid Qdrant URL
+ if (qdrantField) {
+ simulateInput(qdrantField, "http://localhost:6333")
+ }
+
+ // Set API key
+ if (apiKeyField) {
+ simulateInput(apiKeyField, "test-api-key")
+ }
+
+ // Select a model - this is required (get the select element specifically)
+ const modelSelect = screen.getAllByRole("combobox").find((el) => el.tagName === "SELECT")
+ if (modelSelect) {
+ fireEvent.change(modelSelect, { target: { value: "0" } })
+ }
+
+ // Try to save again
+ fireEvent.click(saveButton)
+
+ // Validation errors should be cleared (specific field errors are checked elsewhere)
+ })
+ })
+})
diff --git a/webview-ui/src/components/chat/__tests__/FollowUpSuggest.spec.tsx b/webview-ui/src/components/chat/__tests__/FollowUpSuggest.spec.tsx
new file mode 100644
index 0000000000..aa3f84fd8c
--- /dev/null
+++ b/webview-ui/src/components/chat/__tests__/FollowUpSuggest.spec.tsx
@@ -0,0 +1,414 @@
+import React, { createContext, useContext } from "react"
+import { render, screen, act } from "@testing-library/react"
+
+import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"
+import { FollowUpSuggest } from "../FollowUpSuggest"
+import { TooltipProvider } from "@radix-ui/react-tooltip"
+
+// Mock the translation hook
+vi.mock("@src/i18n/TranslationContext", () => ({
+ TranslationProvider: ({ children }: { children: React.ReactNode }) => children,
+ useAppTranslation: () => ({
+ t: (key: string, options?: any) => {
+ if (key === "chat:followUpSuggest.countdownDisplay" && options?.count !== undefined) {
+ return `${options.count}s`
+ }
+ if (key === "chat:followUpSuggest.autoSelectCountdown" && options?.count !== undefined) {
+ return `Auto-selecting in ${options.count} seconds`
+ }
+ if (key === "chat:followUpSuggest.copyToInput") {
+ return "Copy to input"
+ }
+ return key
+ },
+ }),
+}))
+
+// Test-specific extension state context that only provides the values needed by FollowUpSuggest
+interface TestExtensionState {
+ autoApprovalEnabled: boolean
+ alwaysAllowFollowupQuestions: boolean
+ followupAutoApproveTimeoutMs: number
+}
+
+const TestExtensionStateContext = createContext(undefined)
+
+// Mock the useExtensionState hook to use our test context
+vi.mock("@src/context/ExtensionStateContext", () => ({
+ useExtensionState: () => {
+ const context = useContext(TestExtensionStateContext)
+ if (!context) {
+ throw new Error("useExtensionState must be used within TestExtensionStateProvider")
+ }
+ return context
+ },
+}))
+
+// Test provider that only provides the specific values needed by FollowUpSuggest
+const TestExtensionStateProvider: React.FC<{
+ children: React.ReactNode
+ value: TestExtensionState
+}> = ({ children, value }) => {
+ return {children}
+}
+
+// Helper function to render component with test providers
+const renderWithTestProviders = (component: React.ReactElement, extensionState: TestExtensionState) => {
+ return render(
+
+ {component}
+ ,
+ )
+}
+
+describe("FollowUpSuggest", () => {
+ const mockSuggestions = [{ answer: "First suggestion" }, { answer: "Second suggestion" }]
+
+ const mockOnSuggestionClick = vi.fn()
+ const mockOnCancelAutoApproval = vi.fn()
+
+ // Default test state with auto-approval enabled
+ const defaultTestState: TestExtensionState = {
+ autoApprovalEnabled: true,
+ alwaysAllowFollowupQuestions: true,
+ followupAutoApproveTimeoutMs: 3000, // 3 seconds for testing
+ }
+
+ beforeEach(() => {
+ vi.clearAllMocks()
+ vi.useFakeTimers()
+ })
+
+ afterEach(() => {
+ vi.useRealTimers()
+ })
+
+ it("should display countdown timer when auto-approval is enabled", () => {
+ renderWithTestProviders(
+ ,
+ defaultTestState,
+ )
+
+ // Should show initial countdown (3 seconds)
+ expect(screen.getByText(/3s/)).toBeInTheDocument()
+ })
+
+ it("should not display countdown timer when isAnswered is true", () => {
+ renderWithTestProviders(
+ ,
+ defaultTestState,
+ )
+
+ // Should not show countdown
+ expect(screen.queryByText(/\d+s/)).not.toBeInTheDocument()
+ })
+
+ it("should clear interval and call onCancelAutoApproval when component unmounts", () => {
+ const { unmount } = renderWithTestProviders(
+ ,
+ defaultTestState,
+ )
+
+ // Unmount the component
+ unmount()
+
+ // onCancelAutoApproval should have been called
+ expect(mockOnCancelAutoApproval).toHaveBeenCalled()
+ })
+
+ it("should not show countdown when auto-approval is disabled", () => {
+ const testState: TestExtensionState = {
+ ...defaultTestState,
+ autoApprovalEnabled: false,
+ }
+
+ renderWithTestProviders(
+ ,
+ testState,
+ )
+
+ // Should not show countdown
+ expect(screen.queryByText(/\d+s/)).not.toBeInTheDocument()
+ })
+
+ it("should not show countdown when alwaysAllowFollowupQuestions is false", () => {
+ const testState: TestExtensionState = {
+ ...defaultTestState,
+ alwaysAllowFollowupQuestions: false,
+ }
+
+ renderWithTestProviders(
+ ,
+ testState,
+ )
+
+ // Should not show countdown
+ expect(screen.queryByText(/\d+s/)).not.toBeInTheDocument()
+ })
+
+ it("should use custom timeout value from extension state", () => {
+ const testState: TestExtensionState = {
+ ...defaultTestState,
+ followupAutoApproveTimeoutMs: 5000, // 5 seconds
+ }
+
+ renderWithTestProviders(
+ ,
+ testState,
+ )
+
+ // Should show initial countdown (5 seconds)
+ expect(screen.getByText(/5s/)).toBeInTheDocument()
+ })
+
+ it("should render suggestions without countdown when both auto-approval settings are disabled", () => {
+ const testState: TestExtensionState = {
+ autoApprovalEnabled: false,
+ alwaysAllowFollowupQuestions: false,
+ followupAutoApproveTimeoutMs: 3000,
+ }
+
+ renderWithTestProviders(
+ ,
+ testState,
+ )
+
+ // Should render suggestions
+ expect(screen.getByText("First suggestion")).toBeInTheDocument()
+ expect(screen.getByText("Second suggestion")).toBeInTheDocument()
+
+ // Should not show countdown
+ expect(screen.queryByText(/\d+s/)).not.toBeInTheDocument()
+ })
+
+ it("should not render when no suggestions are provided", () => {
+ const { container } = renderWithTestProviders(
+ ,
+ defaultTestState,
+ )
+
+ // Component should not render anything
+ expect(container.firstChild).toBeNull()
+ })
+
+ it("should not render when onSuggestionClick is not provided", () => {
+ const { container } = renderWithTestProviders(
+ ,
+ defaultTestState,
+ )
+
+ // Component should not render anything
+ expect(container.firstChild).toBeNull()
+ })
+
+ it("should stop countdown when user manually responds (isAnswered becomes true)", () => {
+ const { rerender } = renderWithTestProviders(
+ ,
+ defaultTestState,
+ )
+
+ // Initially should show countdown
+ expect(screen.getByText(/3s/)).toBeInTheDocument()
+
+ // Simulate user manually responding by setting isAnswered to true
+ rerender(
+
+
+
+
+ ,
+ )
+
+ // Countdown should no longer be visible immediately after isAnswered becomes true
+ expect(screen.queryByText(/\d+s/)).not.toBeInTheDocument()
+
+ // Advance timer to ensure countdown doesn't restart or continue
+ vi.advanceTimersByTime(5000)
+
+ // onSuggestionClick should not have been called (auto-selection stopped)
+ expect(mockOnSuggestionClick).not.toHaveBeenCalled()
+
+ // Countdown should still not be visible
+ expect(screen.queryByText(/\d+s/)).not.toBeInTheDocument()
+
+ // Verify onCancelAutoApproval was called when the countdown was stopped
+ expect(mockOnCancelAutoApproval).toHaveBeenCalled()
+ })
+
+ it("should handle race condition when timeout fires but user has already responded", () => {
+ // This test simulates the scenario where:
+ // 1. Auto-approval countdown starts
+ // 2. User manually responds (isAnswered becomes true)
+ // 3. The timeout still fires (because it was already scheduled)
+ // 4. The auto-selection should NOT happen because user already responded
+
+ const { rerender } = renderWithTestProviders(
+ ,
+ defaultTestState,
+ )
+
+ // Initially should show countdown
+ expect(screen.getByText(/3s/)).toBeInTheDocument()
+
+ // Advance timer to just before timeout completes (2.5 seconds)
+ vi.advanceTimersByTime(2500)
+
+ // User manually responds before timeout completes
+ rerender(
+
+
+
+
+ ,
+ )
+
+ // Countdown should be hidden immediately
+ expect(screen.queryByText(/\d+s/)).not.toBeInTheDocument()
+
+ // Now advance timer past the original timeout duration
+ vi.advanceTimersByTime(1000) // Total: 3.5 seconds
+
+ // onSuggestionClick should NOT have been called
+ // This verifies the fix for the race condition
+ expect(mockOnSuggestionClick).not.toHaveBeenCalled()
+ })
+
+ it("should update countdown display as time progresses", async () => {
+ renderWithTestProviders(
+ ,
+ defaultTestState,
+ )
+
+ // Initially should show 3s
+ expect(screen.getByText(/3s/)).toBeInTheDocument()
+
+ // Advance timer by 1 second and wait for React to update
+ await act(async () => {
+ vi.advanceTimersByTime(1000)
+ })
+
+ // Check countdown updated to 2s
+ expect(screen.getByText(/2s/)).toBeInTheDocument()
+
+ // Advance timer by another second
+ await act(async () => {
+ vi.advanceTimersByTime(1000)
+ })
+
+ // Check countdown updated to 1s
+ expect(screen.getByText(/1s/)).toBeInTheDocument()
+
+ // Advance timer to completion - countdown should disappear
+ await act(async () => {
+ vi.advanceTimersByTime(1000)
+ })
+
+ // Countdown should no longer be visible after reaching 0
+ expect(screen.queryByText(/\d+s/)).not.toBeInTheDocument()
+
+ // The component itself doesn't trigger auto-selection, that's handled by ChatView
+ expect(mockOnSuggestionClick).not.toHaveBeenCalled()
+ })
+
+ it("should handle component unmounting during countdown", () => {
+ const { unmount } = renderWithTestProviders(
+ ,
+ defaultTestState,
+ )
+
+ // Initially should show countdown
+ expect(screen.getByText(/3s/)).toBeInTheDocument()
+
+ // Advance timer partially
+ vi.advanceTimersByTime(1500)
+
+ // Unmount component before countdown completes
+ unmount()
+
+ // onCancelAutoApproval should have been called
+ expect(mockOnCancelAutoApproval).toHaveBeenCalled()
+
+ // Advance timer past the original timeout
+ vi.advanceTimersByTime(2000)
+
+ // onSuggestionClick should NOT have been called (component doesn't auto-select)
+ expect(mockOnSuggestionClick).not.toHaveBeenCalled()
+ })
+})
diff --git a/webview-ui/src/components/settings/ApiConfigManager.tsx b/webview-ui/src/components/settings/ApiConfigManager.tsx
index edd0a5fe07..e737678c01 100644
--- a/webview-ui/src/components/settings/ApiConfigManager.tsx
+++ b/webview-ui/src/components/settings/ApiConfigManager.tsx
@@ -1,28 +1,12 @@
import { memo, useEffect, useRef, useState } from "react"
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
-import { ChevronsUpDown, Check, X, AlertTriangle } from "lucide-react"
+import { AlertTriangle } from "lucide-react"
import type { ProviderSettingsEntry, OrganizationAllowList } from "@roo-code/types"
import { useAppTranslation } from "@/i18n/TranslationContext"
-import { cn } from "@/lib/utils"
-import {
- Button,
- Input,
- Dialog,
- DialogContent,
- DialogTitle,
- Command,
- CommandEmpty,
- CommandGroup,
- CommandInput,
- CommandItem,
- CommandList,
- Popover,
- PopoverContent,
- PopoverTrigger,
- StandardTooltip,
-} from "@/components/ui"
+import { Button, Input, Dialog, DialogContent, DialogTitle, StandardTooltip, SearchableSelect } from "@/components/ui"
+import type { SearchableSelectOption } from "@/components/ui"
interface ApiConfigManagerProps {
currentApiConfigName?: string
@@ -50,12 +34,8 @@ const ApiConfigManager = ({
const [inputValue, setInputValue] = useState("")
const [newProfileName, setNewProfileName] = useState("")
const [error, setError] = useState(null)
- const [open, setOpen] = useState(false)
- const [searchValue, setSearchValue] = useState("")
const inputRef = useRef(null)
const newProfileInputRef = useRef(null)
- const searchInputRef = useRef(null)
- const searchResetTimeoutRef = useRef(null)
// Check if a profile is valid based on the organization allow list
const isProfileValid = (profile: ProviderSettingsEntry): boolean => {
@@ -128,42 +108,10 @@ const ApiConfigManager = ({
useEffect(() => {
resetCreateState()
resetRenameState()
- // Reset search value when current profile changes
- const timeoutId = setTimeout(() => setSearchValue(""), 100)
- return () => clearTimeout(timeoutId)
}, [currentApiConfigName])
- // Cleanup timeout on unmount
- useEffect(() => {
- return () => {
- if (searchResetTimeoutRef.current) {
- clearTimeout(searchResetTimeoutRef.current)
- }
- }
- }, [])
-
- const onOpenChange = (open: boolean) => {
- setOpen(open)
-
- // Reset search when closing the popover
- if (!open) {
- // Clear any existing timeout
- if (searchResetTimeoutRef.current) {
- clearTimeout(searchResetTimeoutRef.current)
- }
- searchResetTimeoutRef.current = setTimeout(() => setSearchValue(""), 100)
- }
- }
-
- const onClearSearch = () => {
- setSearchValue("")
- searchInputRef.current?.focus()
- }
-
const handleSelectConfig = (configName: string) => {
if (!configName) return
-
- setOpen(false)
onSelectConfig(configName)
}
@@ -278,95 +226,30 @@ const ApiConfigManager = ({
) : (
<>
-
-
-
-
-
-
-
-
- {searchValue.length > 0 && (
-
-
-
- )}
-
-
-
- {searchValue && (
-
- {t("settings:providers.noMatchFound")}
-
- )}
-
-
- {listApiConfigMeta
- .filter((config) =>
- searchValue
- ? config.name.toLowerCase().includes(searchValue.toLowerCase())
- : true,
- )
- .map((config) => {
- const valid = isProfileValid(config)
- return (
-
-
- {!valid && (
-
-
-
-
-
- )}
- {config.name}
-
-
-
- )
- })}
-
-
-
-
-
+
{
+ const valid = isProfileValid(config)
+ return {
+ value: config.name,
+ label: config.name,
+ disabled: !valid,
+ icon: !valid ? (
+
+
+
+
+
+ ) : undefined,
+ } as SearchableSelectOption
+ })}
+ placeholder={t("settings:common.select")}
+ searchPlaceholder={t("settings:providers.searchPlaceholder")}
+ emptyMessage={t("settings:providers.noMatchFound")}
+ className="grow"
+ data-testid="select-component"
+ />
{errorMessage && }
diff --git a/webview-ui/src/components/settings/AutoApproveSettings.tsx b/webview-ui/src/components/settings/AutoApproveSettings.tsx
index 71283a833b..3521653892 100644
--- a/webview-ui/src/components/settings/AutoApproveSettings.tsx
+++ b/webview-ui/src/components/settings/AutoApproveSettings.tsx
@@ -26,6 +26,7 @@ type AutoApproveSettingsProps = HTMLAttributes & {
alwaysAllowSubtasks?: boolean
alwaysAllowExecute?: boolean
alwaysAllowFollowupQuestions?: boolean
+ alwaysAllowUpdateTodoList?: boolean
followupAutoApproveTimeoutMs?: number
allowedCommands?: string[]
setCachedStateField: SetCachedStateField<
@@ -65,6 +66,7 @@ export const AutoApproveSettings = ({
alwaysAllowExecute,
alwaysAllowFollowupQuestions,
followupAutoApproveTimeoutMs = 60000,
+ alwaysAllowUpdateTodoList,
allowedCommands,
setCachedStateField,
...props
@@ -103,6 +105,7 @@ export const AutoApproveSettings = ({
alwaysAllowSubtasks={alwaysAllowSubtasks}
alwaysAllowExecute={alwaysAllowExecute}
alwaysAllowFollowupQuestions={alwaysAllowFollowupQuestions}
+ alwaysAllowUpdateTodoList={alwaysAllowUpdateTodoList}
onToggle={(key, value) => setCachedStateField(key, value)}
/>
diff --git a/webview-ui/src/components/settings/ExperimentalSettings.tsx b/webview-ui/src/components/settings/ExperimentalSettings.tsx
index 958c7742fd..53801232ec 100644
--- a/webview-ui/src/components/settings/ExperimentalSettings.tsx
+++ b/webview-ui/src/components/settings/ExperimentalSettings.tsx
@@ -1,40 +1,26 @@
import { HTMLAttributes } from "react"
import { FlaskConical } from "lucide-react"
-import { VSCodeCheckbox, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
-import { Trans } from "react-i18next"
-import type { Experiments, CodebaseIndexConfig, CodebaseIndexModels } from "@roo-code/types"
+import type { Experiments } from "@roo-code/types"
import { EXPERIMENT_IDS, experimentConfigsMap } from "@roo/experiments"
import { useAppTranslation } from "@src/i18n/TranslationContext"
import { cn } from "@src/lib/utils"
-import { buildDocLink } from "@src/utils/docLinks"
import { SetExperimentEnabled } from "./types"
import { SectionHeader } from "./SectionHeader"
import { Section } from "./Section"
import { ExperimentalFeature } from "./ExperimentalFeature"
-import { SetCachedStateField } from "./types"
type ExperimentalSettingsProps = HTMLAttributes & {
experiments: Experiments
setExperimentEnabled: SetExperimentEnabled
- // CodeIndexSettings props
- codebaseIndexModels: CodebaseIndexModels | undefined
- codebaseIndexConfig: CodebaseIndexConfig | undefined
- // For codebase index enabled toggle
- codebaseIndexEnabled?: boolean
- setCachedStateField?: SetCachedStateField
}
export const ExperimentalSettings = ({
experiments,
setExperimentEnabled,
- codebaseIndexModels,
- codebaseIndexConfig,
- codebaseIndexEnabled,
- setCachedStateField,
className,
...props
}: ExperimentalSettingsProps) => {
@@ -79,32 +65,6 @@ export const ExperimentalSettings = ({
/>
)
})}
-
- {/* Codebase Indexing Enable/Disable Toggle */}
-
-
- {
- const newEnabledState = e.target.checked
- if (setCachedStateField && codebaseIndexConfig) {
- setCachedStateField("codebaseIndexConfig", {
- ...codebaseIndexConfig,
- codebaseIndexEnabled: newEnabledState,
- })
- }
- }}>
- {t("settings:codeIndex.enableLabel")}
-
-
-
-
-
-
-
-
)
diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx
index 3ece8146af..8550be1e1b 100644
--- a/webview-ui/src/components/settings/SettingsView.tsx
+++ b/webview-ui/src/components/settings/SettingsView.tsx
@@ -170,11 +170,10 @@ const SettingsView = forwardRef
(({ onDone, t
maxConcurrentFileReads,
condensingApiConfigId,
customCondensingPrompt,
- codebaseIndexConfig,
- codebaseIndexModels,
customSupportPrompts,
profileThresholds,
alwaysAllowFollowupQuestions,
+ alwaysAllowUpdateTodoList,
followupAutoApproveTimeoutMs,
} = cachedState
@@ -314,15 +313,13 @@ const SettingsView = forwardRef(({ onDone, t
vscode.postMessage({ type: "alwaysAllowModeSwitch", bool: alwaysAllowModeSwitch })
vscode.postMessage({ type: "alwaysAllowSubtasks", bool: alwaysAllowSubtasks })
vscode.postMessage({ type: "alwaysAllowFollowupQuestions", bool: alwaysAllowFollowupQuestions })
+ vscode.postMessage({ type: "alwaysAllowUpdateTodoList", bool: alwaysAllowUpdateTodoList })
vscode.postMessage({ type: "followupAutoApproveTimeoutMs", value: followupAutoApproveTimeoutMs })
vscode.postMessage({ type: "condensingApiConfigId", text: condensingApiConfigId || "" })
vscode.postMessage({ type: "updateCondensingPrompt", text: customCondensingPrompt || "" })
vscode.postMessage({ type: "updateSupportPrompt", values: customSupportPrompts || {} })
vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration })
vscode.postMessage({ type: "telemetrySetting", text: telemetrySetting })
- if (codebaseIndexConfig) {
- vscode.postMessage({ type: "codebaseIndexEnabled", bool: codebaseIndexConfig.codebaseIndexEnabled })
- }
vscode.postMessage({ type: "profileThresholds", values: profileThresholds })
setChangeDetected(false)
}
@@ -606,6 +603,7 @@ const SettingsView = forwardRef(({ onDone, t
alwaysAllowSubtasks={alwaysAllowSubtasks}
alwaysAllowExecute={alwaysAllowExecute}
alwaysAllowFollowupQuestions={alwaysAllowFollowupQuestions}
+ alwaysAllowUpdateTodoList={alwaysAllowUpdateTodoList}
followupAutoApproveTimeoutMs={followupAutoApproveTimeoutMs}
allowedCommands={allowedCommands}
setCachedStateField={setCachedStateField}
@@ -688,14 +686,7 @@ const SettingsView = forwardRef(({ onDone, t
{/* Experimental Section */}
{activeTab === "experimental" && (
-
+
)}
{/* Language Section */}
diff --git a/webview-ui/src/components/settings/__tests__/ApiConfigManager.spec.tsx b/webview-ui/src/components/settings/__tests__/ApiConfigManager.spec.tsx
index 194f0ff31e..152d853444 100644
--- a/webview-ui/src/components/settings/__tests__/ApiConfigManager.spec.tsx
+++ b/webview-ui/src/components/settings/__tests__/ApiConfigManager.spec.tsx
@@ -89,6 +89,21 @@ vitest.mock("@/components/ui", () => ({
{children}
),
+ SearchableSelect: ({ value, onValueChange, options, placeholder, "data-testid": dataTestId }: any) => (
+
+ ),
}))
describe("ApiConfigManager", () => {
@@ -243,20 +258,11 @@ describe("ApiConfigManager", () => {
it("allows selecting a different config", () => {
render()
- // Click the select component to open the dropdown
- const selectButton = screen.getByTestId("select-component")
- fireEvent.click(selectButton)
+ // The SearchableSelect mock renders as a simple select element
+ const selectElement = screen.getByTestId("select-component") as HTMLSelectElement
- // Find all command items and click the one with "Another Config"
- const commandItems = document.querySelectorAll(".command-item")
- // Find the item with "Another Config" text
- const anotherConfigItem = Array.from(commandItems).find((item) => item.textContent?.includes("Another Config"))
-
- if (!anotherConfigItem) {
- throw new Error("Could not find 'Another Config' option")
- }
-
- fireEvent.click(anotherConfigItem)
+ // Change the select value to "Another Config"
+ fireEvent.change(selectElement, { target: { value: "Another Config" } })
expect(mockOnSelectConfig).toHaveBeenCalledWith("Another Config")
})
diff --git a/webview-ui/src/components/settings/__tests__/ApiOptions.spec.tsx b/webview-ui/src/components/settings/__tests__/ApiOptions.spec.tsx
index 1e13323f36..07331b8e42 100644
--- a/webview-ui/src/components/settings/__tests__/ApiOptions.spec.tsx
+++ b/webview-ui/src/components/settings/__tests__/ApiOptions.spec.tsx
@@ -88,6 +88,18 @@ vi.mock("@/components/ui", () => ({
onChange(parseFloat(e.target.value))} />
),
+ SearchableSelect: ({ value, onValueChange, options, placeholder, "data-testid": dataTestId }: any) => (
+
+
+
+ ),
}))
vi.mock("../TemperatureControl", () => ({
@@ -291,6 +303,32 @@ describe("ApiOptions", () => {
// since we have separate tests for that component. We just need to verify that
// it's included in the ApiOptions component when appropriate.
})
+ it("filters providers by search input and shows no match message when appropriate", () => {
+ renderApiOptions({
+ apiConfiguration: {},
+ setApiConfigurationField: () => {},
+ })
+
+ // The SearchableSelect mock renders inside a div with the test id
+ const providerSelectContainer = screen.getByTestId("provider-select")
+ expect(providerSelectContainer).toBeInTheDocument()
+
+ // Get the actual select element inside the container
+ const providerSelect = providerSelectContainer.querySelector("select") as HTMLSelectElement
+ expect(providerSelect).toBeInTheDocument()
+
+ // Check that we have options
+ const options = providerSelect.querySelectorAll("option")
+ expect(options.length).toBeGreaterThan(1) // Should have placeholder + actual options
+
+ // Check that OpenAI option exists
+ const optionTexts = Array.from(options).map((opt) => opt.textContent)
+ expect(optionTexts).toContain("OpenAI")
+ expect(optionTexts).toContain("Anthropic")
+
+ // Note: The mock doesn't implement search functionality, so we're just verifying
+ // that the select element is rendered with the expected options
+ })
describe("OpenAI provider tests", () => {
it("removes reasoningEffort from openAiCustomModelInfo when unchecked", () => {
diff --git a/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx b/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx
index 0a76e54ffe..404b3a6883 100644
--- a/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx
+++ b/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx
@@ -102,6 +102,21 @@ vi.mock("../../../components/common/Tab", () => ({
vi.mock("@/components/ui", () => ({
...vi.importActual("@/components/ui"),
+ Popover: ({ children }: any) =>
{children}
,
+ PopoverTrigger: ({ children }: any) =>
{children}
,
+ PopoverContent: ({ children }: any) =>
{children}
,
+ Command: ({ children }: any) =>
{children}
,
+ CommandInput: ({ value, onValueChange }: any) => (
+
onValueChange(e.target.value)} />
+ ),
+ CommandGroup: ({ children }: any) =>
{children}
,
+ CommandItem: ({ children, onSelect }: any) => (
+
+ {children}
+
+ ),
+ CommandList: ({ children }: any) =>
{children}
,
+ CommandEmpty: ({ children }: any) =>
{children}
,
Slider: ({ value, onValueChange, "data-testid": dataTestId }: any) => (
({
),
SelectTrigger: ({ children }: any) =>
{children}
,
SelectValue: ({ placeholder }: any) =>
{placeholder}
,
+ SearchableSelect: ({ value, onValueChange, options, placeholder }: any) => (
+
+ ),
AlertDialog: ({ children, open }: any) => (
{children}
diff --git a/webview-ui/src/components/ui/index.ts b/webview-ui/src/components/ui/index.ts
index 5bd6b62ee8..c36d3b4769 100644
--- a/webview-ui/src/components/ui/index.ts
+++ b/webview-ui/src/components/ui/index.ts
@@ -10,6 +10,7 @@ export * from "./dropdown-menu"
export * from "./input"
export * from "./popover"
export * from "./progress"
+export * from "./searchable-select"
export * from "./separator"
export * from "./slider"
export * from "./select-dropdown"
diff --git a/webview-ui/src/components/ui/searchable-select.tsx b/webview-ui/src/components/ui/searchable-select.tsx
new file mode 100644
index 0000000000..7317dda781
--- /dev/null
+++ b/webview-ui/src/components/ui/searchable-select.tsx
@@ -0,0 +1,176 @@
+import * as React from "react"
+import { Check, ChevronDown, X } from "lucide-react"
+import { cn } from "@/lib/utils"
+import {
+ Button,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui"
+
+export interface SearchableSelectOption {
+ value: string
+ label: string
+ disabled?: boolean
+ icon?: React.ReactNode
+}
+
+interface SearchableSelectProps {
+ value?: string
+ onValueChange: (value: string) => void
+ options: SearchableSelectOption[]
+ placeholder: string
+ searchPlaceholder: string
+ emptyMessage: string
+ className?: string
+ disabled?: boolean
+ "data-testid"?: string
+}
+
+export function SearchableSelect({
+ value,
+ onValueChange,
+ options,
+ placeholder,
+ searchPlaceholder,
+ emptyMessage,
+ className,
+ disabled,
+ "data-testid": dataTestId,
+}: SearchableSelectProps) {
+ const [open, setOpen] = React.useState(false)
+ const [searchValue, setSearchValue] = React.useState("")
+ const searchInputRef = React.useRef
(null)
+ const searchResetTimeoutRef = React.useRef(null)
+ const isMountedRef = React.useRef(true)
+
+ // Find the selected option
+ const selectedOption = options.find((option) => option.value === value)
+
+ // Filter options based on search
+ const filteredOptions = React.useMemo(() => {
+ if (!searchValue) return options
+ return options.filter((option) => option.label.toLowerCase().includes(searchValue.toLowerCase()))
+ }, [options, searchValue])
+
+ // Cleanup timeout on unmount
+ React.useEffect(() => {
+ return () => {
+ isMountedRef.current = false
+ if (searchResetTimeoutRef.current) {
+ clearTimeout(searchResetTimeoutRef.current)
+ }
+ }
+ }, [])
+
+ // Reset search when value changes
+ React.useEffect(() => {
+ const timeoutId = setTimeout(() => {
+ if (isMountedRef.current) {
+ setSearchValue("")
+ }
+ }, 100)
+ return () => clearTimeout(timeoutId)
+ }, [value])
+
+ const handleOpenChange = (open: boolean) => {
+ setOpen(open)
+ // Reset search when closing
+ if (!open) {
+ if (searchResetTimeoutRef.current) {
+ clearTimeout(searchResetTimeoutRef.current)
+ }
+ searchResetTimeoutRef.current = setTimeout(() => setSearchValue(""), 100)
+ }
+ }
+
+ const handleSelect = (selectedValue: string) => {
+ setOpen(false)
+ onValueChange(selectedValue)
+ }
+
+ const handleClearSearch = () => {
+ setSearchValue("")
+ searchInputRef.current?.focus()
+ }
+
+ return (
+
+
+
+
+
+
+
+
+ {searchValue.length > 0 && (
+
+
+
+ )}
+
+
+
+ {searchValue && {emptyMessage}
}
+
+
+ {filteredOptions.map((option) => (
+ handleSelect(option.value)}
+ disabled={option.disabled}
+ className={option.disabled ? "text-vscode-errorForeground" : ""}>
+
+ {option.icon}
+ {option.label}
+
+
+
+ ))}
+
+
+
+
+
+ )
+}
diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx
index df7cee5627..bf927211c2 100644
--- a/webview-ui/src/context/ExtensionStateContext.tsx
+++ b/webview-ui/src/context/ExtensionStateContext.tsx
@@ -214,7 +214,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
autoCondenseContextPercent: 100,
profileThresholds: {},
codebaseIndexConfig: {
- codebaseIndexEnabled: false,
+ codebaseIndexEnabled: true,
codebaseIndexQdrantUrl: "http://localhost:6333",
codebaseIndexEmbedderProvider: "openai",
codebaseIndexEmbedderBaseUrl: "",
diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json
index 1dd892a39f..848306a1cf 100644
--- a/webview-ui/src/i18n/locales/ca/chat.json
+++ b/webview-ui/src/i18n/locales/ca/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} Llançat",
"description": "Roo Code {{version}} porta noves funcions potents i millores significatives per millorar el vostre flux de treball de desenvolupament.",
"whatsNew": "Novetats",
- "feature1": "Compartició de Tasques amb 1 Clic: Comparteix instantàniament les vostres tasques amb companys i la comunitat amb un sol clic.",
- "feature2": "Suport per a Directori Global .roo: Carrega regles i configuracions des d'un directori global .roo per a configuracions consistents entre projectes.",
+ "feature1": "Indexació de Base de Codi Graduada d'Experimental: La indexació completa de la base de codi ara és estable i està llesta per a ús en producció amb cerca millorada i comprensió del context.",
+ "feature2": "Nova Funcionalitat de Llista de Tasques Pendents: Mantingueu les vostres tasques en el bon camí amb gestió integrada de tasques pendents que us ajuda a mantenir-vos organitzats i centrats en els vostres objectius de desenvolupament.",
"feature3": "Transicions Millorades d'Arquitecte a Codi: Transferències fluides de la planificació en mode Arquitecte a la implementació en mode Codi.",
"hideButton": "Amaga l'anunci",
"detailsDiscussLinks": "Obtén més detalls i uneix-te a les discussions a Discord i Reddit 🚀"
diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json
index dfca7f9a43..57b5dadaae 100644
--- a/webview-ui/src/i18n/locales/ca/settings.json
+++ b/webview-ui/src/i18n/locales/ca/settings.json
@@ -98,6 +98,21 @@
"error": "Error"
},
"close": "Tancar",
+ "validation": {
+ "invalidQdrantUrl": "URL de Qdrant no vàlida",
+ "invalidOllamaUrl": "URL d'Ollama no vàlida",
+ "invalidBaseUrl": "URL de base no vàlida",
+ "qdrantUrlRequired": "Cal una URL de Qdrant",
+ "openaiApiKeyRequired": "Cal una clau d'API d'OpenAI",
+ "modelSelectionRequired": "Cal seleccionar un model",
+ "apiKeyRequired": "Cal una clau d'API",
+ "modelIdRequired": "Cal un ID de model",
+ "modelDimensionRequired": "Cal una dimensió de model",
+ "geminiApiKeyRequired": "Cal una clau d'API de Gemini",
+ "ollamaBaseUrlRequired": "Cal una URL base d'Ollama",
+ "baseUrlRequired": "Cal una URL base",
+ "modelDimensionMinValue": "La dimensió del model ha de ser superior a 0"
+ },
"advancedConfigLabel": "Configuració avançada",
"searchMinScoreLabel": "Llindar de puntuació de cerca",
"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.",
@@ -191,6 +206,8 @@
"createProfile": "Crea perfil",
"cannotDeleteOnlyProfile": "No es pot eliminar l'únic perfil",
"searchPlaceholder": "Cerca perfils",
+ "searchProviderPlaceholder": "Cerca proveïdors",
+ "noProviderMatchFound": "No s'han trobat proveïdors",
"noMatchFound": "No s'han trobat perfils coincidents",
"vscodeLmDescription": "L'API del model de llenguatge de VS Code us permet executar models proporcionats per altres extensions de VS Code (incloent-hi, però no limitat a, GitHub Copilot). La manera més senzilla de començar és instal·lar les extensions Copilot i Copilot Chat des del VS Code Marketplace.",
"awsCustomArnUse": "Introduïu un ARN vàlid d'Amazon Bedrock per al model que voleu utilitzar. Exemples de format:",
diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json
index c62fe9d3bb..f28448ce54 100644
--- a/webview-ui/src/i18n/locales/de/chat.json
+++ b/webview-ui/src/i18n/locales/de/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} veröffentlicht",
"description": "Roo Code {{version}} bringt mächtige neue Funktionen und bedeutende Verbesserungen, um deinen Entwicklungsworkflow zu verbessern.",
"whatsNew": "Was ist neu",
- "feature1": "1-Klick-Aufgaben-Teilen: Teile deine Aufgaben sofort mit Kollegen und der Community mit einem einzigen Klick.",
- "feature2": "Globale .roo-Verzeichnis-Unterstützung: Lade Regeln und Konfigurationen aus einem globalen .roo-Verzeichnis für konsistente Einstellungen über Projekte hinweg.",
+ "feature1": "Codebase-Indizierung aus experimentellem Status graduiert: Die vollständige Codebase-Indizierung ist jetzt stabil und bereit für den Produktionseinsatz mit verbesserter Suche und Kontextverständnis.",
+ "feature2": "Neue Todo-Listen-Funktion: Behalte deine Aufgaben im Blick mit integriertem Todo-Management, das dir hilft, organisiert und fokussiert auf deine Entwicklungsziele zu bleiben.",
"feature3": "Verbesserte Architect-zu-Code-Übergänge: Nahtlose Übergaben von der Planung im Architect-Modus zur Implementierung im Code-Modus.",
"hideButton": "Ankündigung ausblenden",
"detailsDiscussLinks": "Erhalte mehr Details und diskutiere auf Discord und Reddit 🚀"
diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json
index 0b2f0bf889..8d57652ba2 100644
--- a/webview-ui/src/i18n/locales/de/settings.json
+++ b/webview-ui/src/i18n/locales/de/settings.json
@@ -98,6 +98,21 @@
"error": "Fehler"
},
"close": "Schließen",
+ "validation": {
+ "invalidQdrantUrl": "Ungültige Qdrant-URL",
+ "invalidOllamaUrl": "Ungültige Ollama-URL",
+ "invalidBaseUrl": "Ungültige Basis-URL",
+ "qdrantUrlRequired": "Qdrant-URL ist erforderlich",
+ "openaiApiKeyRequired": "OpenAI-API-Schlüssel ist erforderlich",
+ "modelSelectionRequired": "Modellauswahl ist erforderlich",
+ "apiKeyRequired": "API-Schlüssel ist erforderlich",
+ "modelIdRequired": "Modell-ID ist erforderlich",
+ "modelDimensionRequired": "Modellabmessung ist erforderlich",
+ "geminiApiKeyRequired": "Gemini-API-Schlüssel ist erforderlich",
+ "ollamaBaseUrlRequired": "Ollama-Basis-URL ist erforderlich",
+ "baseUrlRequired": "Basis-URL ist erforderlich",
+ "modelDimensionMinValue": "Modellabmessung muss größer als 0 sein"
+ },
"advancedConfigLabel": "Erweiterte Konfiguration",
"searchMinScoreLabel": "Suchergebnis-Schwellenwert",
"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.",
@@ -191,6 +206,8 @@
"createProfile": "Profil erstellen",
"cannotDeleteOnlyProfile": "Das einzige Profil kann nicht gelöscht werden",
"searchPlaceholder": "Profile durchsuchen",
+ "searchProviderPlaceholder": "Suchanbieter durchsuchen",
+ "noProviderMatchFound": "Keine Anbieter gefunden",
"noMatchFound": "Keine passenden Profile gefunden",
"vscodeLmDescription": "Die VS Code Language Model API ermöglicht das Ausführen von Modellen, die von anderen VS Code-Erweiterungen bereitgestellt werden (einschließlich, aber nicht beschränkt auf GitHub Copilot). Der einfachste Weg, um zu starten, besteht darin, die Erweiterungen Copilot und Copilot Chat aus dem VS Code Marketplace zu installieren.",
"awsCustomArnUse": "Geben Sie eine gültige Amazon Bedrock ARN für das Modell ein, das Sie verwenden möchten. Formatbeispiele:",
diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json
index ea4f8920f5..0c49fbaac7 100644
--- a/webview-ui/src/i18n/locales/en/chat.json
+++ b/webview-ui/src/i18n/locales/en/chat.json
@@ -247,9 +247,8 @@
"title": "🎉 Roo Code {{version}} Released",
"description": "Roo Code {{version}} brings powerful new features and significant improvements to enhance your development workflow.",
"whatsNew": "What's New",
- "feature1": "1-Click Task Sharing: Share your tasks instantly with colleagues and the community with a single click.",
- "feature2": "Global .roo Directory Support: Load rules and configurations from a global .roo directory for consistent settings across projects.",
- "feature3": "Improved Architect to Code Transitions: Seamless handoffs from planning in Architect mode to implementation in Code mode.",
+ "feature1": "Codebase Indexing Graduated from Experimental: Full codebase indexing is now stable and ready for production use with improved search and context understanding.",
+ "feature2": "New Todo List Feature: Keep your tasks on track with integrated todo management that helps you stay organized and focused on your development goals.",
"hideButton": "Hide announcement",
"detailsDiscussLinks": "Get more details and discuss in Discord and Reddit 🚀"
},
diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json
index 8b30f87a7e..da40058b00 100644
--- a/webview-ui/src/i18n/locales/en/settings.json
+++ b/webview-ui/src/i18n/locales/en/settings.json
@@ -104,7 +104,22 @@
"indexed": "Indexed",
"error": "Error"
},
- "close": "Close"
+ "close": "Close",
+ "validation": {
+ "qdrantUrlRequired": "Qdrant URL is required",
+ "invalidQdrantUrl": "Invalid Qdrant URL",
+ "invalidOllamaUrl": "Invalid Ollama URL",
+ "invalidBaseUrl": "Invalid base URL",
+ "openaiApiKeyRequired": "OpenAI API key is required",
+ "modelSelectionRequired": "Model selection is required",
+ "apiKeyRequired": "API key is required",
+ "modelIdRequired": "Model ID is required",
+ "modelDimensionRequired": "Model dimension is required",
+ "geminiApiKeyRequired": "Gemini API key is required",
+ "ollamaBaseUrlRequired": "Ollama base URL is required",
+ "baseUrlRequired": "Base URL is required",
+ "modelDimensionMinValue": "Model dimension must be greater than 0"
+ }
},
"autoApprove": {
"description": "Allow Roo to automatically perform operations without requiring approval. Enable these settings only if you fully trust the AI and understand the associated security risks.",
@@ -191,6 +206,8 @@
"createProfile": "Create Profile",
"cannotDeleteOnlyProfile": "Cannot delete the only profile",
"searchPlaceholder": "Search profiles",
+ "searchProviderPlaceholder": "Search providers",
+ "noProviderMatchFound": "No providers found",
"noMatchFound": "No matching profiles found",
"vscodeLmDescription": " The VS Code Language Model API allows you to run models provided by other VS Code extensions (including but not limited to GitHub Copilot). The easiest way to get started is to install the Copilot and Copilot Chat extensions from the VS Code Marketplace.",
"awsCustomArnUse": "Enter a valid Amazon Bedrock ARN for the model you want to use. Format examples:",
diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json
index a4349b13dc..71a26f6c10 100644
--- a/webview-ui/src/i18n/locales/es/chat.json
+++ b/webview-ui/src/i18n/locales/es/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} publicado",
"description": "Roo Code {{version}} trae poderosas nuevas funcionalidades y mejoras significativas para mejorar tu flujo de trabajo de desarrollo.",
"whatsNew": "Novedades",
- "feature1": "Compartir tareas con 1 clic: Comparte tus tareas instantáneamente con colegas y la comunidad con un solo clic.",
- "feature2": "Soporte de directorio .roo global: Carga reglas y configuraciones desde un directorio .roo global para configuraciones consistentes entre proyectos.",
+ "feature1": "Indexación de código base graduada de experimental: La indexación completa del código base ahora es estable y está lista para uso en producción con búsqueda mejorada y comprensión de contexto.",
+ "feature2": "Nueva función de lista de tareas: Mantén tus tareas en el buen camino con gestión integrada de tareas que te ayuda a mantenerte organizado y enfocado en tus objetivos de desarrollo.",
"feature3": "Transiciones mejoradas de Arquitecto a Código: Transferencias fluidas desde la planificación en modo Arquitecto hasta la implementación en modo Código.",
"hideButton": "Ocultar anuncio",
"detailsDiscussLinks": "Obtén más detalles y participa en Discord y Reddit 🚀"
diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json
index 14aa34278d..b91d0e055f 100644
--- a/webview-ui/src/i18n/locales/es/settings.json
+++ b/webview-ui/src/i18n/locales/es/settings.json
@@ -98,6 +98,21 @@
"error": "Error"
},
"close": "Cerrar",
+ "validation": {
+ "invalidQdrantUrl": "URL de Qdrant no válida",
+ "invalidOllamaUrl": "URL de Ollama no válida",
+ "invalidBaseUrl": "URL base no válida",
+ "qdrantUrlRequired": "Se requiere la URL de Qdrant",
+ "openaiApiKeyRequired": "Se requiere la clave API de OpenAI",
+ "modelSelectionRequired": "Se requiere la selección de un modelo",
+ "apiKeyRequired": "Se requiere la clave API",
+ "modelIdRequired": "Se requiere el ID del modelo",
+ "modelDimensionRequired": "Se requiere la dimensión del modelo",
+ "geminiApiKeyRequired": "Se requiere la clave API de Gemini",
+ "ollamaBaseUrlRequired": "Se requiere la URL base de Ollama",
+ "baseUrlRequired": "Se requiere la URL base",
+ "modelDimensionMinValue": "La dimensión del modelo debe ser mayor que 0"
+ },
"advancedConfigLabel": "Configuración avanzada",
"searchMinScoreLabel": "Umbral de puntuación de búsqueda",
"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.",
@@ -191,6 +206,8 @@
"createProfile": "Crear perfil",
"cannotDeleteOnlyProfile": "No se puede eliminar el único perfil",
"searchPlaceholder": "Buscar perfiles",
+ "searchProviderPlaceholder": "Buscar proveedores",
+ "noProviderMatchFound": "No se encontraron proveedores",
"noMatchFound": "No se encontraron perfiles coincidentes",
"vscodeLmDescription": "La API del Modelo de Lenguaje de VS Code le permite ejecutar modelos proporcionados por otras extensiones de VS Code (incluido, entre otros, GitHub Copilot). La forma más sencilla de empezar es instalar las extensiones Copilot y Copilot Chat desde el VS Code Marketplace.",
"awsCustomArnUse": "Ingrese un ARN de Amazon Bedrock válido para el modelo que desea utilizar. Ejemplos de formato:",
diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json
index b5f06354bb..19531f2554 100644
--- a/webview-ui/src/i18n/locales/fr/chat.json
+++ b/webview-ui/src/i18n/locales/fr/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} est sortie",
"description": "Roo Code {{version}} apporte de puissantes nouvelles fonctionnalités et des améliorations significatives pour améliorer ton flux de travail de développement.",
"whatsNew": "Quoi de neuf",
- "feature1": "Partage de tâches en 1 clic : Partage tes tâches instantanément avec tes collègues et la communauté en un seul clic.",
- "feature2": "Support du répertoire .roo global : Charge les règles et configurations depuis un répertoire .roo global pour des paramètres cohérents entre les projets.",
+ "feature1": "L'indexation de la base de code sort du statut expérimental : L'indexation complète de la base de code est maintenant stable et prête pour un usage en production avec une recherche améliorée et une meilleure compréhension du contexte.",
+ "feature2": "Nouvelle fonctionnalité de liste de tâches : Garde tes tâches sur la bonne voie avec une gestion intégrée des tâches qui t'aide à rester organisé et concentré sur tes objectifs de développement.",
"feature3": "Transitions Architecte vers Code améliorées : Transferts fluides de la planification en mode Architecte vers l'implémentation en mode Code.",
"hideButton": "Masquer l'annonce",
"detailsDiscussLinks": "Obtenez plus de détails et participez aux discussions sur Discord et Reddit 🚀"
diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json
index d645235dbe..d4940567c6 100644
--- a/webview-ui/src/i18n/locales/fr/settings.json
+++ b/webview-ui/src/i18n/locales/fr/settings.json
@@ -98,6 +98,21 @@
"error": "Erreur"
},
"close": "Fermer",
+ "validation": {
+ "invalidQdrantUrl": "URL Qdrant invalide",
+ "invalidOllamaUrl": "URL Ollama invalide",
+ "invalidBaseUrl": "URL de base invalide",
+ "qdrantUrlRequired": "L'URL Qdrant est requise",
+ "openaiApiKeyRequired": "La clé API OpenAI est requise",
+ "modelSelectionRequired": "La sélection du modèle est requise",
+ "apiKeyRequired": "La clé API est requise",
+ "modelIdRequired": "L'ID du modèle est requis",
+ "modelDimensionRequired": "La dimension du modèle est requise",
+ "geminiApiKeyRequired": "La clé API Gemini est requise",
+ "ollamaBaseUrlRequired": "L'URL de base Ollama est requise",
+ "baseUrlRequired": "L'URL de base est requise",
+ "modelDimensionMinValue": "La dimension du modèle doit être supérieure à 0"
+ },
"advancedConfigLabel": "Configuration avancée",
"searchMinScoreLabel": "Seuil de score de recherche",
"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.",
@@ -191,6 +206,8 @@
"createProfile": "Créer un profil",
"cannotDeleteOnlyProfile": "Impossible de supprimer le seul profil",
"searchPlaceholder": "Rechercher des profils",
+ "searchProviderPlaceholder": "Rechercher des fournisseurs",
+ "noProviderMatchFound": "Aucun fournisseur trouvé",
"noMatchFound": "Aucun profil correspondant trouvé",
"vscodeLmDescription": "L'API du modèle de langage VS Code vous permet d'exécuter des modèles fournis par d'autres extensions VS Code (y compris, mais sans s'y limiter, GitHub Copilot). Le moyen le plus simple de commencer est d'installer les extensions Copilot et Copilot Chat depuis le VS Code Marketplace.",
"awsCustomArnUse": "Entrez un ARN Amazon Bedrock valide pour le modèle que vous souhaitez utiliser. Exemples de format :",
diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json
index 9afdcbdd38..a45317d2da 100644
--- a/webview-ui/src/i18n/locales/hi/chat.json
+++ b/webview-ui/src/i18n/locales/hi/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} रिलीज़ हुआ",
"description": "Roo Code {{version}} आपके विकास वर्कफ़्लो को बेहतर बनाने के लिए शक्तिशाली नई सुविधाएं और महत्वपूर्ण सुधार लेकर आया है।",
"whatsNew": "नया क्या है",
- "feature1": "1-क्लिक टास्क शेयरिंग: अपने टास्क को सहकर्मियों और समुदाय के साथ एक क्लिक में तुरंत साझा करें।",
- "feature2": "ग्लोबल .roo डायरेक्टरी समर्थन: प्रोजेक्ट्स में निरंतर सेटिंग्स के लिए ग्लोबल .roo डायरेक्टरी से नियम और कॉन्फ़िगरेशन लोड करें।",
+ "feature1": "कोडबेस इंडेक्सिंग प्रयोगात्मक से स्नातक: पूर्ण कोडबेस इंडेक्सिंग अब स्थिर है और बेहतर खोज और संदर्भ समझ के साथ उत्पादन उपयोग के लिए तैयार है।",
+ "feature2": "नई टूडू सूची सुविधा: एकीकृत टूडू प्रबंधन के साथ अपने कार्यों को ट्रैक पर रखें जो आपको व्यवस्थित रहने और अपने विकास लक्ष्यों पर केंद्रित रहने में मदद करता है।",
"feature3": "बेहतर आर्किटेक्ट से कोड ट्रांज़िशन: आर्किटेक्ट मोड में प्लानिंग से कोड मोड में इम्प्लीमेंटेशन तक सहज स्थानांतरण।",
"hideButton": "घोषणा छुपाएं",
"detailsDiscussLinks": "Discord और Reddit पर अधिक विवरण प्राप्त करें और चर्चाओं में शामिल हों 🚀"
diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json
index 20bb0b0e70..8665afc990 100644
--- a/webview-ui/src/i18n/locales/hi/settings.json
+++ b/webview-ui/src/i18n/locales/hi/settings.json
@@ -98,6 +98,21 @@
"error": "त्रुटि"
},
"close": "बंद करें",
+ "validation": {
+ "invalidQdrantUrl": "अमान्य Qdrant URL",
+ "invalidOllamaUrl": "अमान्य Ollama URL",
+ "invalidBaseUrl": "अमान्य बेस URL",
+ "qdrantUrlRequired": "Qdrant URL आवश्यक है",
+ "openaiApiKeyRequired": "OpenAI API कुंजी आवश्यक है",
+ "modelSelectionRequired": "मॉडल चयन आवश्यक है",
+ "apiKeyRequired": "API कुंजी आवश्यक है",
+ "modelIdRequired": "मॉडल आईडी आवश्यक है",
+ "modelDimensionRequired": "मॉडल आयाम आवश्यक है",
+ "geminiApiKeyRequired": "Gemini API कुंजी आवश्यक है",
+ "ollamaBaseUrlRequired": "Ollama आधार URL आवश्यक है",
+ "baseUrlRequired": "आधार URL आवश्यक है",
+ "modelDimensionMinValue": "मॉडल आयाम 0 से बड़ा होना चाहिए"
+ },
"advancedConfigLabel": "उन्नत कॉन्फ़िगरेशन",
"searchMinScoreLabel": "खोज स्कोर थ्रेसहोल्ड",
"searchMinScoreDescription": "खोज परिणामों के लिए आवश्यक न्यूनतम समानता स्कोर (0.0-1.0)। कम मान अधिक परिणाम लौटाते हैं लेकिन कम प्रासंगिक हो सकते हैं। उच्च मान कम लेकिन अधिक प्रासंगिक परिणाम लौटाते हैं।",
@@ -191,6 +206,8 @@
"createProfile": "प्रोफ़ाइल बनाएं",
"cannotDeleteOnlyProfile": "केवल एकमात्र प्रोफ़ाइल को हटाया नहीं जा सकता",
"searchPlaceholder": "प्रोफ़ाइल खोजें",
+ "searchProviderPlaceholder": "प्रदाता खोजें",
+ "noProviderMatchFound": "कोई प्रदाता नहीं मिला",
"noMatchFound": "कोई मिलान प्रोफ़ाइल नहीं मिला",
"vscodeLmDescription": "VS कोड भाषा मॉडल API आपको अन्य VS कोड एक्सटेंशन (जैसे GitHub Copilot) द्वारा प्रदान किए गए मॉडल चलाने की अनुमति देता है। शुरू करने का सबसे आसान तरीका VS कोड मार्केटप्लेस से Copilot और Copilot चैट एक्सटेंशन इंस्टॉल करना है।",
"awsCustomArnUse": "आप जिस मॉडल का उपयोग करना चाहते हैं, उसके लिए एक वैध AWS बेडरॉक ARN दर्ज करें। प्रारूप उदाहरण:",
diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json
index fc0bd5056f..7df325b7f9 100644
--- a/webview-ui/src/i18n/locales/id/chat.json
+++ b/webview-ui/src/i18n/locales/id/chat.json
@@ -253,8 +253,8 @@
"title": "🎉 Roo Code {{version}} Dirilis",
"description": "Roo Code {{version}} menghadirkan fitur-fitur baru yang kuat dan peningkatan signifikan untuk meningkatkan alur kerja pengembangan Anda.",
"whatsNew": "Yang Baru",
- "feature1": "Berbagi Tugas 1-Klik: Bagikan tugas Anda secara instan dengan rekan kerja dan komunitas hanya dengan satu klik.",
- "feature2": "Dukungan Direktori Global .roo: Muat aturan dan konfigurasi dari direktori global .roo untuk pengaturan yang konsisten di seluruh proyek.",
+ "feature1": "Pengindeksan Codebase Lulus dari Eksperimental: Pengindeksan codebase lengkap kini stabil dan siap untuk penggunaan produksi dengan pencarian yang ditingkatkan dan pemahaman konteks.",
+ "feature2": "Fitur Daftar Todo Baru: Jaga tugas Anda tetap pada jalur dengan manajemen todo terintegrasi yang membantu Anda tetap terorganisir dan fokus pada tujuan pengembangan.",
"feature3": "Transisi Arsitektur ke Kode yang Ditingkatkan: Transfer yang mulus dari perencanaan di mode Arsitektur ke implementasi di mode Kode.",
"hideButton": "Sembunyikan pengumuman",
"detailsDiscussLinks": "Dapatkan detail lebih lanjut dan bergabung dalam diskusi di Discord dan Reddit 🚀"
diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json
index a8adf2e626..199751e384 100644
--- a/webview-ui/src/i18n/locales/id/settings.json
+++ b/webview-ui/src/i18n/locales/id/settings.json
@@ -98,6 +98,21 @@
"error": "Error"
},
"close": "Tutup",
+ "validation": {
+ "invalidQdrantUrl": "URL Qdrant tidak valid",
+ "invalidOllamaUrl": "URL Ollama tidak valid",
+ "invalidBaseUrl": "URL dasar tidak valid",
+ "qdrantUrlRequired": "URL Qdrant diperlukan",
+ "openaiApiKeyRequired": "Kunci API OpenAI diperlukan",
+ "modelSelectionRequired": "Pemilihan model diperlukan",
+ "apiKeyRequired": "Kunci API diperlukan",
+ "modelIdRequired": "ID Model diperlukan",
+ "modelDimensionRequired": "Dimensi model diperlukan",
+ "geminiApiKeyRequired": "Kunci API Gemini diperlukan",
+ "ollamaBaseUrlRequired": "URL dasar Ollama diperlukan",
+ "baseUrlRequired": "URL dasar diperlukan",
+ "modelDimensionMinValue": "Dimensi model harus lebih besar dari 0"
+ },
"advancedConfigLabel": "Konfigurasi Lanjutan",
"searchMinScoreLabel": "Ambang Batas Skor Pencarian",
"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.",
@@ -195,6 +210,8 @@
"createProfile": "Buat Profil",
"cannotDeleteOnlyProfile": "Tidak dapat menghapus satu-satunya profil",
"searchPlaceholder": "Cari profil",
+ "searchProviderPlaceholder": "Cari penyedia",
+ "noProviderMatchFound": "Tidak ada penyedia ditemukan",
"noMatchFound": "Tidak ada profil yang cocok ditemukan",
"vscodeLmDescription": " API Model Bahasa VS Code memungkinkan kamu menjalankan model yang disediakan oleh ekstensi VS Code lainnya (termasuk namun tidak terbatas pada GitHub Copilot). Cara termudah untuk memulai adalah menginstal ekstensi Copilot dan Copilot Chat dari VS Code Marketplace.",
"awsCustomArnUse": "Masukkan ARN Amazon Bedrock yang valid untuk model yang ingin kamu gunakan. Contoh format:",
diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json
index f49a25dfa6..4b368f214f 100644
--- a/webview-ui/src/i18n/locales/it/chat.json
+++ b/webview-ui/src/i18n/locales/it/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Rilasciato Roo Code {{version}}",
"description": "Roo Code {{version}} porta nuove potenti funzionalità e miglioramenti significativi per potenziare il tuo flusso di lavoro di sviluppo.",
"whatsNew": "Novità",
- "feature1": "Condivisione Task con 1 Clic: Condividi istantaneamente i tuoi task con colleghi e la community con un solo clic.",
- "feature2": "Supporto Directory Globale .roo: Carica regole e configurazioni da una directory globale .roo per impostazioni coerenti tra progetti.",
+ "feature1": "Indicizzazione Codebase Promossa da Sperimentale: L'indicizzazione completa del codebase è ora stabile e pronta per l'uso in produzione con ricerca migliorata e comprensione del contesto.",
+ "feature2": "Nuova Funzione Lista Todo: Mantieni i tuoi task in carreggiata con la gestione integrata dei todo che ti aiuta a rimanere organizzato e concentrato sui tuoi obiettivi di sviluppo.",
"feature3": "Transizioni Migliorate da Architetto a Codice: Trasferimenti fluidi dalla pianificazione in modalità Architetto all'implementazione in modalità Codice.",
"hideButton": "Nascondi annuncio",
"detailsDiscussLinks": "Ottieni maggiori dettagli e partecipa alle discussioni su Discord e Reddit 🚀"
diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json
index 48b9e324b0..48a4c8e4db 100644
--- a/webview-ui/src/i18n/locales/it/settings.json
+++ b/webview-ui/src/i18n/locales/it/settings.json
@@ -98,6 +98,21 @@
"error": "Errore"
},
"close": "Chiudi",
+ "validation": {
+ "invalidQdrantUrl": "URL Qdrant non valido",
+ "invalidOllamaUrl": "URL Ollama non valido",
+ "invalidBaseUrl": "URL di base non valido",
+ "qdrantUrlRequired": "È richiesto l'URL di Qdrant",
+ "openaiApiKeyRequired": "È richiesta la chiave API di OpenAI",
+ "modelSelectionRequired": "È richiesta la selezione del modello",
+ "apiKeyRequired": "È richiesta la chiave API",
+ "modelIdRequired": "È richiesto l'ID del modello",
+ "modelDimensionRequired": "È richiesta la dimensione del modello",
+ "geminiApiKeyRequired": "È richiesta la chiave API Gemini",
+ "ollamaBaseUrlRequired": "È richiesto l'URL di base di Ollama",
+ "baseUrlRequired": "È richiesto l'URL di base",
+ "modelDimensionMinValue": "La dimensione del modello deve essere maggiore di 0"
+ },
"advancedConfigLabel": "Configurazione avanzata",
"searchMinScoreLabel": "Soglia punteggio di ricerca",
"searchMinScoreDescription": "Punteggio minimo di somiglianza (0.0-1.0) richiesto per i risultati della ricerca. Valori più bassi restituiscono più risultati ma potrebbero essere meno pertinenti. Valori più alti restituiscono meno risultati ma più pertinenti.",
@@ -192,6 +207,8 @@
"cannotDeleteOnlyProfile": "Impossibile eliminare l'unico profilo",
"searchPlaceholder": "Cerca profili",
"noMatchFound": "Nessun profilo corrispondente trovato",
+ "searchProviderPlaceholder": "Cerca fornitori",
+ "noProviderMatchFound": "Nessun fornitore trovato",
"vscodeLmDescription": "L'API del Modello di Linguaggio di VS Code consente di eseguire modelli forniti da altre estensioni di VS Code (incluso, ma non limitato a, GitHub Copilot). Il modo più semplice per iniziare è installare le estensioni Copilot e Copilot Chat dal VS Code Marketplace.",
"awsCustomArnUse": "Inserisci un ARN Amazon Bedrock valido per il modello che desideri utilizzare. Esempi di formato:",
"awsCustomArnDesc": "Assicurati che la regione nell'ARN corrisponda alla regione AWS selezionata sopra.",
diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json
index cb5ebcdafd..5a19b64945 100644
--- a/webview-ui/src/i18n/locales/ja/chat.json
+++ b/webview-ui/src/i18n/locales/ja/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} リリース",
"description": "Roo Code {{version}}は、開発ワークフローを向上させる強力な新機能と重要な改善をもたらします。",
"whatsNew": "新機能",
- "feature1": "1クリックタスク共有: ワンクリックで同僚やコミュニティとタスクを瞬時に共有できます。",
- "feature2": "グローバル.rooディレクトリサポート: グローバル.rooディレクトリからルールと設定を読み込み、プロジェクト間で一貫した設定を実現。",
+ "feature1": "コードベースインデックス機能が実験段階を卒業: 完全なコードベースインデックス機能が安定し、改善された検索とコンテキスト理解により本番環境での使用が可能になりました。",
+ "feature2": "新しいTodoリスト機能: 統合されたTodo管理でタスクを軌道に乗せ、開発目標に整理され集中した状態を維持できます。",
"feature3": "改善されたアーキテクトからコードへの移行: アーキテクトモードでの計画からコードモードでの実装へのシームレスな引き継ぎ。",
"hideButton": "通知を非表示",
"detailsDiscussLinks": "詳細はDiscordとRedditでご確認・ディスカッションください 🚀"
diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json
index 666d650bc4..397ce67f62 100644
--- a/webview-ui/src/i18n/locales/ja/settings.json
+++ b/webview-ui/src/i18n/locales/ja/settings.json
@@ -98,6 +98,21 @@
"error": "エラー"
},
"close": "閉じる",
+ "validation": {
+ "invalidQdrantUrl": "無効なQdrant URL",
+ "invalidOllamaUrl": "無効なOllama URL",
+ "invalidBaseUrl": "無効なベースURL",
+ "qdrantUrlRequired": "Qdrant URL が必要です",
+ "openaiApiKeyRequired": "OpenAI APIキーが必要です",
+ "modelSelectionRequired": "モデルの選択が必要です",
+ "apiKeyRequired": "APIキーが必要です",
+ "modelIdRequired": "モデルIDが必要です",
+ "modelDimensionRequired": "モデルの次元が必要です",
+ "geminiApiKeyRequired": "Gemini APIキーが必要です",
+ "ollamaBaseUrlRequired": "OllamaのベースURLが必要です",
+ "baseUrlRequired": "ベースURLが必要です",
+ "modelDimensionMinValue": "モデルの次元は0より大きくなければなりません"
+ },
"advancedConfigLabel": "詳細設定",
"searchMinScoreLabel": "検索スコアのしきい値",
"searchMinScoreDescription": "検索結果に必要な最小類似度スコア(0.0-1.0)。値を低くするとより多くの結果が返されますが、関連性が低くなる可能性があります。値を高くすると返される結果は少なくなりますが、より関連性が高くなります。",
@@ -191,6 +206,8 @@
"createProfile": "プロファイルを作成",
"cannotDeleteOnlyProfile": "唯一のプロファイルは削除できません",
"searchPlaceholder": "プロファイルを検索",
+ "searchProviderPlaceholder": "プロバイダーを検索",
+ "noProviderMatchFound": "プロバイダーが見つかりません",
"noMatchFound": "一致するプロファイルが見つかりません",
"vscodeLmDescription": "VS Code言語モデルAPIを使用すると、他のVS Code拡張機能(GitHub Copilotなど)が提供するモデルを実行できます。最も簡単な方法は、VS Code MarketplaceからCopilotおよびCopilot Chat拡張機能をインストールすることです。",
"awsCustomArnUse": "使用したいモデルの有効なAmazon Bedrock ARNを入力してください。形式の例:",
diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json
index 1f86dc8cf4..f3ed7699ca 100644
--- a/webview-ui/src/i18n/locales/ko/chat.json
+++ b/webview-ui/src/i18n/locales/ko/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} 출시",
"description": "Roo Code {{version}}은 개발 워크플로우를 향상시키는 강력한 새 기능과 중요한 개선사항을 제공합니다.",
"whatsNew": "새로운 기능",
- "feature1": "원클릭 작업 공유: 한 번의 클릭으로 동료 및 커뮤니티와 작업을 즉시 공유하세요.",
- "feature2": "글로벌 .roo 디렉토리 지원: 글로벌 .roo 디렉토리에서 규칙과 구성을 로드하여 프로젝트 간 일관된 설정을 유지하세요.",
+ "feature1": "코드베이스 인덱싱이 실험 단계에서 졸업: 전체 코드베이스 인덱싱이 이제 안정적이며 향상된 검색 및 컨텍스트 이해 기능으로 프로덕션 사용이 준비되었습니다.",
+ "feature2": "새로운 할 일 목록 기능: 통합된 할 일 관리로 작업을 궤도에 유지하여 개발 목표에 체계적이고 집중된 상태를 유지하세요.",
"feature3": "개선된 아키텍트에서 코드로의 전환: 아키텍트 모드에서의 계획부터 코드 모드에서의 구현까지 원활한 인수인계.",
"hideButton": "공지 숨기기",
"detailsDiscussLinks": "Discord와 Reddit에서 자세한 내용을 확인하고 토론에 참여하세요 🚀"
diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json
index a1618952ef..746cea65ad 100644
--- a/webview-ui/src/i18n/locales/ko/settings.json
+++ b/webview-ui/src/i18n/locales/ko/settings.json
@@ -98,6 +98,21 @@
"error": "오류"
},
"close": "닫기",
+ "validation": {
+ "invalidQdrantUrl": "잘못된 Qdrant URL",
+ "invalidOllamaUrl": "잘못된 Ollama URL",
+ "invalidBaseUrl": "잘못된 기본 URL",
+ "qdrantUrlRequired": "Qdrant URL이 필요합니다",
+ "openaiApiKeyRequired": "OpenAI API 키가 필요합니다",
+ "modelSelectionRequired": "모델 선택이 필요합니다",
+ "apiKeyRequired": "API 키가 필요합니다",
+ "modelIdRequired": "모델 ID가 필요합니다",
+ "modelDimensionRequired": "모델 차원이 필요합니다",
+ "geminiApiKeyRequired": "Gemini API 키가 필요합니다",
+ "ollamaBaseUrlRequired": "Ollama 기본 URL이 필요합니다",
+ "baseUrlRequired": "기본 URL이 필요합니다",
+ "modelDimensionMinValue": "모델 차원은 0보다 커야 합니다"
+ },
"advancedConfigLabel": "고급 구성",
"searchMinScoreLabel": "검색 점수 임계값",
"searchMinScoreDescription": "검색 결과에 필요한 최소 유사도 점수(0.0-1.0). 값이 낮을수록 더 많은 결과가 반환되지만 관련성이 떨어질 수 있습니다. 값이 높을수록 결과는 적지만 관련성이 높은 결과가 반환됩니다.",
@@ -191,6 +206,8 @@
"createProfile": "프로필 생성",
"cannotDeleteOnlyProfile": "유일한 프로필은 삭제할 수 없습니다",
"searchPlaceholder": "프로필 검색",
+ "searchProviderPlaceholder": "공급자 검색",
+ "noProviderMatchFound": "공급자를 찾을 수 없습니다",
"noMatchFound": "일치하는 프로필이 없습니다",
"vscodeLmDescription": "VS Code 언어 모델 API를 사용하면 GitHub Copilot을 포함한 기타 VS Code 확장 프로그램이 제공하는 모델을 실행할 수 있습니다. 시작하려면 VS Code 마켓플레이스에서 Copilot 및 Copilot Chat 확장 프로그램을 설치하는 것이 가장 쉽습니다.",
"awsCustomArnUse": "사용하려는 모델의 유효한 Amazon Bedrock ARN을 입력하세요. 형식 예시:",
diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json
index d228d7b0c2..874fb74bc7 100644
--- a/webview-ui/src/i18n/locales/nl/chat.json
+++ b/webview-ui/src/i18n/locales/nl/chat.json
@@ -227,8 +227,8 @@
"title": "🎉 Roo Code {{version}} uitgebracht",
"description": "Roo Code {{version}} brengt krachtige nieuwe functies en significante verbeteringen om je ontwikkelingsworkflow te verbeteren.",
"whatsNew": "Wat is er nieuw",
- "feature1": "1-Klik Taak Delen: Deel je taken direct met collega's en de community met slechts één klik.",
- "feature2": "Globale .roo Directory Ondersteuning: Laad regels en configuraties vanuit een globale .roo directory voor consistente instellingen tussen projecten.",
+ "feature1": "Codebase Indexering Afgestudeerd van Experimenteel: Volledige codebase indexering is nu stabiel en klaar voor productiegebruik met verbeterde zoekfunctionaliteit en contextbegrip.",
+ "feature2": "Nieuwe Todo Lijst Functie: Houd je taken op koers met geïntegreerd todo-beheer dat je helpt georganiseerd en gefocust te blijven op je ontwikkelingsdoelen.",
"feature3": "Verbeterde Architect naar Code Overgangen: Soepele overdrachten van planning in Architect modus naar implementatie in Code modus.",
"hideButton": "Aankondiging verbergen",
"detailsDiscussLinks": "Krijg meer details en doe mee aan discussies op Discord en Reddit 🚀"
diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json
index 2fb43272ce..c5315205ca 100644
--- a/webview-ui/src/i18n/locales/nl/settings.json
+++ b/webview-ui/src/i18n/locales/nl/settings.json
@@ -98,6 +98,21 @@
"error": "Fout"
},
"close": "Sluiten",
+ "validation": {
+ "invalidQdrantUrl": "Ongeldige Qdrant URL",
+ "invalidOllamaUrl": "Ongeldige Ollama URL",
+ "invalidBaseUrl": "Ongeldige basis-URL",
+ "qdrantUrlRequired": "Qdrant URL is vereist",
+ "openaiApiKeyRequired": "OpenAI API-sleutel is vereist",
+ "modelSelectionRequired": "Modelselectie is vereist",
+ "apiKeyRequired": "API-sleutel is vereist",
+ "modelIdRequired": "Model-ID is vereist",
+ "modelDimensionRequired": "Modelafmeting is vereist",
+ "geminiApiKeyRequired": "Gemini API-sleutel is vereist",
+ "ollamaBaseUrlRequired": "Ollama basis-URL is vereist",
+ "baseUrlRequired": "Basis-URL is vereist",
+ "modelDimensionMinValue": "Modelafmeting moet groter zijn dan 0"
+ },
"advancedConfigLabel": "Geavanceerde configuratie",
"searchMinScoreLabel": "Zoekscore drempel",
"searchMinScoreDescription": "Minimale overeenkomstscore (0.0-1.0) vereist voor zoekresultaten. Lagere waarden leveren meer resultaten op, maar zijn mogelijk minder relevant. Hogere waarden leveren minder, maar relevantere resultaten op.",
@@ -191,6 +206,8 @@
"createProfile": "Profiel aanmaken",
"cannotDeleteOnlyProfile": "Kan het enige profiel niet verwijderen",
"searchPlaceholder": "Zoek profielen",
+ "searchProviderPlaceholder": "Zoek providers",
+ "noProviderMatchFound": "Geen providers gevonden",
"noMatchFound": "Geen overeenkomende profielen gevonden",
"vscodeLmDescription": "De VS Code Language Model API stelt je in staat modellen te draaien die door andere VS Code-extensies worden geleverd (waaronder GitHub Copilot). De eenvoudigste manier om te beginnen is door de Copilot- en Copilot Chat-extensies te installeren vanuit de VS Code Marketplace.",
"awsCustomArnUse": "Voer een geldige Amazon Bedrock ARN in voor het model dat je wilt gebruiken. Voorbeeldformaten:",
diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json
index fdb39b0851..254f18c9ba 100644
--- a/webview-ui/src/i18n/locales/pl/chat.json
+++ b/webview-ui/src/i18n/locales/pl/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} wydany",
"description": "Roo Code {{version}} wprowadza potężne nowe funkcje i znaczące ulepszenia, aby ulepszyć Twój przepływ pracy programistycznej.",
"whatsNew": "Co nowego",
- "feature1": "Udostępnianie zadań jednym kliknięciem: Natychmiast udostępniaj swoje zadania współpracownikom i społeczności jednym kliknięciem.",
- "feature2": "Wsparcie globalnego katalogu .roo: Ładuj reguły i konfiguracje z globalnego katalogu .roo dla spójnych ustawień między projektami.",
+ "feature1": "Indeksowanie bazy kodu ukończone z fazy eksperymentalnej: Pełne indeksowanie bazy kodu jest teraz stabilne i gotowe do użytku produkcyjnego z ulepszonymi funkcjami wyszukiwania i rozumienia kontekstu.",
+ "feature2": "Nowa funkcja listy zadań: Utrzymuj swoje zadania na właściwym torze dzięki zintegrowanemu zarządzaniu zadaniami, które pomaga ci pozostać zorganizowanym i skupionym na celach rozwojowych.",
"feature3": "Ulepszone przejścia z Architekta do Kodu: Płynne transfery z planowania w trybie Architekta do implementacji w trybie Kodu.",
"hideButton": "Ukryj ogłoszenie",
"detailsDiscussLinks": "Uzyskaj więcej szczegółów i dołącz do dyskusji na Discord i Reddit 🚀"
diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json
index 3988da53c2..1829c23ba4 100644
--- a/webview-ui/src/i18n/locales/pl/settings.json
+++ b/webview-ui/src/i18n/locales/pl/settings.json
@@ -98,6 +98,21 @@
"error": "Błąd"
},
"close": "Zamknij",
+ "validation": {
+ "invalidQdrantUrl": "Nieprawidłowy URL Qdrant",
+ "invalidOllamaUrl": "Nieprawidłowy URL Ollama",
+ "invalidBaseUrl": "Nieprawidłowy podstawowy URL",
+ "qdrantUrlRequired": "Wymagany jest URL Qdrant",
+ "openaiApiKeyRequired": "Wymagany jest klucz API OpenAI",
+ "modelSelectionRequired": "Wymagany jest wybór modelu",
+ "apiKeyRequired": "Wymagany jest klucz API",
+ "modelIdRequired": "Wymagane jest ID modelu",
+ "modelDimensionRequired": "Wymagany jest wymiar modelu",
+ "geminiApiKeyRequired": "Wymagany jest klucz API Gemini",
+ "ollamaBaseUrlRequired": "Wymagany jest bazowy adres URL Ollama",
+ "baseUrlRequired": "Wymagany jest bazowy adres URL",
+ "modelDimensionMinValue": "Wymiar modelu musi być większy niż 0"
+ },
"advancedConfigLabel": "Konfiguracja zaawansowana",
"searchMinScoreLabel": "Próg wyniku wyszukiwania",
"searchMinScoreDescription": "Minimalny wynik podobieństwa (0.0-1.0) wymagany dla wyników wyszukiwania. Niższe wartości zwracają więcej wyników, ale mogą być mniej trafne. Wyższe wartości zwracają mniej wyników, ale bardziej trafnych.",
@@ -191,6 +206,8 @@
"createProfile": "Utwórz profil",
"cannotDeleteOnlyProfile": "Nie można usunąć jedynego profilu",
"searchPlaceholder": "Szukaj profili",
+ "searchProviderPlaceholder": "Szukaj dostawców",
+ "noProviderMatchFound": "Nie znaleziono dostawców",
"noMatchFound": "Nie znaleziono pasujących profili",
"vscodeLmDescription": "Interfejs API modelu językowego VS Code umożliwia uruchamianie modeli dostarczanych przez inne rozszerzenia VS Code (w tym, ale nie tylko, GitHub Copilot). Najłatwiejszym sposobem na rozpoczęcie jest zainstalowanie rozszerzeń Copilot i Copilot Chat z VS Code Marketplace.",
"awsCustomArnUse": "Wprowadź prawidłowy Amazon Bedrock ARN dla modelu, którego chcesz użyć. Przykłady formatu:",
diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json
index b37879f2f0..bebfe0c722 100644
--- a/webview-ui/src/i18n/locales/pt-BR/chat.json
+++ b/webview-ui/src/i18n/locales/pt-BR/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} Lançado",
"description": "Roo Code {{version}} traz novos recursos poderosos e melhorias significativas para aprimorar seu fluxo de trabalho de desenvolvimento.",
"whatsNew": "O que há de novo",
- "feature1": "Compartilhamento de Tarefas com 1 Clique: Compartilhe instantaneamente suas tarefas com colegas e a comunidade com apenas um clique.",
- "feature2": "Suporte a Diretório Global .roo: Carregue regras e configurações de um diretório global .roo para configurações consistentes entre projetos.",
+ "feature1": "Indexação de Base de Código Graduada do Experimental: A indexação completa da base de código agora é estável e pronta para uso em produção com busca aprimorada e compreensão de contexto.",
+ "feature2": "Nova Funcionalidade de Lista de Tarefas: Mantenha suas tarefas no caminho certo com gerenciamento integrado de tarefas que ajuda você a se manter organizado e focado em seus objetivos de desenvolvimento.",
"feature3": "Transições Aprimoradas de Arquiteto para Código: Transferências suaves do planejamento no modo Arquiteto para implementação no modo Código.",
"hideButton": "Ocultar anúncio",
"detailsDiscussLinks": "Obtenha mais detalhes e participe da discussão no Discord e Reddit 🚀"
diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json
index d3553c0c7b..6e46cc8c3e 100644
--- a/webview-ui/src/i18n/locales/pt-BR/settings.json
+++ b/webview-ui/src/i18n/locales/pt-BR/settings.json
@@ -98,6 +98,21 @@
"error": "Erro"
},
"close": "Fechar",
+ "validation": {
+ "invalidQdrantUrl": "URL do Qdrant inválida",
+ "invalidOllamaUrl": "URL do Ollama inválida",
+ "invalidBaseUrl": "URL base inválida",
+ "qdrantUrlRequired": "A URL do Qdrant é obrigatória",
+ "openaiApiKeyRequired": "A chave de API da OpenAI é obrigatória",
+ "modelSelectionRequired": "A seleção do modelo é obrigatória",
+ "apiKeyRequired": "A chave de API é obrigatória",
+ "modelIdRequired": "O ID do modelo é obrigatório",
+ "modelDimensionRequired": "A dimensão do modelo é obrigatória",
+ "geminiApiKeyRequired": "A chave de API do Gemini é obrigatória",
+ "ollamaBaseUrlRequired": "A URL base do Ollama é obrigatória",
+ "baseUrlRequired": "A URL base é obrigatória",
+ "modelDimensionMinValue": "A dimensão do modelo deve ser maior que 0"
+ },
"advancedConfigLabel": "Configuração Avançada",
"searchMinScoreLabel": "Limite de pontuação de busca",
"searchMinScoreDescription": "Pontuação mínima de similaridade (0.0-1.0) necessária para os resultados da busca. Valores mais baixos retornam mais resultados, mas podem ser menos relevantes. Valores mais altos retornam menos resultados, mas mais relevantes.",
@@ -191,6 +206,8 @@
"createProfile": "Criar perfil",
"cannotDeleteOnlyProfile": "Não é possível excluir o único perfil",
"searchPlaceholder": "Pesquisar perfis",
+ "searchProviderPlaceholder": "Pesquisar provedores",
+ "noProviderMatchFound": "Nenhum provedor encontrado",
"noMatchFound": "Nenhum perfil correspondente encontrado",
"vscodeLmDescription": "A API do Modelo de Linguagem do VS Code permite executar modelos fornecidos por outras extensões do VS Code (incluindo, mas não se limitando, ao GitHub Copilot). A maneira mais fácil de começar é instalar as extensões Copilot e Copilot Chat no VS Code Marketplace.",
"awsCustomArnUse": "Insira um ARN Amazon Bedrock válido para o modelo que deseja usar. Exemplos de formato:",
diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json
index 5865e41a53..4ac8f4854a 100644
--- a/webview-ui/src/i18n/locales/ru/chat.json
+++ b/webview-ui/src/i18n/locales/ru/chat.json
@@ -227,8 +227,8 @@
"title": "🎉 Выпущен Roo Code {{version}}",
"description": "Roo Code {{version}} приносит мощные новые функции и значительные улучшения для совершенствования вашего рабочего процесса разработки.",
"whatsNew": "Что нового",
- "feature1": "Обмен задачами в 1 клик: Мгновенно делитесь своими задачами с коллегами и сообществом одним кликом.",
- "feature2": "Поддержка глобального каталога .roo: Загружайте правила и конфигурации из глобального каталога .roo для согласованных настроек между проектами.",
+ "feature1": "Индексация кодовой базы выпущена из экспериментального статуса: Полная индексация кодовой базы теперь стабильна и готова к использованию в продакшене с улучшенным поиском и пониманием контекста.",
+ "feature2": "Новая функция списка задач: Держите свои задачи на правильном пути с интегрированным управлением задачами, которое помогает оставаться организованным и сосредоточенным на целях разработки.",
"feature3": "Улучшенные переходы от Архитектора к Коду: Плавные переходы от планирования в режиме Архитектора к реализации в режиме Кода.",
"hideButton": "Скрыть объявление",
"detailsDiscussLinks": "Подробнее и обсуждение в Discord и Reddit 🚀"
diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json
index 16483222a3..e0a897c2e5 100644
--- a/webview-ui/src/i18n/locales/ru/settings.json
+++ b/webview-ui/src/i18n/locales/ru/settings.json
@@ -98,6 +98,21 @@
"error": "Ошибка"
},
"close": "Закрыть",
+ "validation": {
+ "invalidQdrantUrl": "Неверный URL Qdrant",
+ "invalidOllamaUrl": "Неверный URL Ollama",
+ "invalidBaseUrl": "Неверный базовый URL",
+ "qdrantUrlRequired": "Требуется URL Qdrant",
+ "openaiApiKeyRequired": "Требуется ключ API OpenAI",
+ "modelSelectionRequired": "Требуется выбор модели",
+ "apiKeyRequired": "Требуется ключ API",
+ "modelIdRequired": "Требуется идентификатор модели",
+ "modelDimensionRequired": "Требуется размерность модели",
+ "geminiApiKeyRequired": "Требуется ключ API Gemini",
+ "ollamaBaseUrlRequired": "Требуется базовый URL Ollama",
+ "baseUrlRequired": "Требуется базовый URL",
+ "modelDimensionMinValue": "Размерность модели должна быть больше 0"
+ },
"advancedConfigLabel": "Расширенная конфигурация",
"searchMinScoreLabel": "Порог оценки поиска",
"searchMinScoreDescription": "Минимальный балл сходства (0.0-1.0), необходимый для результатов поиска. Более низкие значения возвращают больше результатов, но они могут быть менее релевантными. Более высокие значения возвращают меньше результатов, но более релевантных.",
@@ -191,6 +206,8 @@
"createProfile": "Создать профиль",
"cannotDeleteOnlyProfile": "Нельзя удалить единственный профиль",
"searchPlaceholder": "Поиск профилей",
+ "searchProviderPlaceholder": "Поиск провайдеров",
+ "noProviderMatchFound": "Провайдеры не найдены",
"noMatchFound": "Совпадений не найдено",
"vscodeLmDescription": "API языковой модели VS Code позволяет запускать модели, предоставляемые другими расширениями VS Code (включая, но не ограничиваясь GitHub Copilot). Для начала установите расширения Copilot и Copilot Chat из VS Code Marketplace.",
"awsCustomArnUse": "Введите действительный Amazon Bedrock ARN для используемой модели. Примеры формата:",
diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json
index 6c5bd20353..56a9f54cb7 100644
--- a/webview-ui/src/i18n/locales/tr/chat.json
+++ b/webview-ui/src/i18n/locales/tr/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} Yayınlandı",
"description": "Roo Code {{version}}, geliştirme iş akışınızı geliştirmek için güçlü yeni özellikler ve önemli iyileştirmeler getiriyor.",
"whatsNew": "Yenilikler",
- "feature1": "Tek Tıkla Görev Paylaşımı: Görevlerinizi meslektaşlarınız ve toplulukla tek tıkla anında paylaşın.",
- "feature2": "Global .roo Dizin Desteği: Projeler arası tutarlı ayarlar için global .roo dizininden kurallar ve yapılandırmalar yükleyin.",
+ "feature1": "Kod Tabanı İndeksleme Deneysel Aşamadan Mezun Oldu: Tam kod tabanı indeksleme artık kararlı ve geliştirilmiş arama ve bağlam anlayışı ile üretim kullanımına hazır.",
+ "feature2": "Yeni Yapılacaklar Listesi Özelliği: Görevlerinizi yolunda tutmak için entegre yapılacaklar yönetimi ile organize kalın ve geliştirme hedeflerinize odaklanın.",
"feature3": "Geliştirilmiş Mimar'dan Kod'a Geçişler: Mimar modunda planlamadan Kod modunda uygulamaya sorunsuz aktarımlar.",
"hideButton": "Duyuruyu gizle",
"detailsDiscussLinks": "Discord ve Reddit'te daha fazla ayrıntı alın ve tartışmalara katılın 🚀"
diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json
index 91ccceb08e..486991ec0d 100644
--- a/webview-ui/src/i18n/locales/tr/settings.json
+++ b/webview-ui/src/i18n/locales/tr/settings.json
@@ -98,6 +98,21 @@
"error": "Hata"
},
"close": "Kapat",
+ "validation": {
+ "invalidQdrantUrl": "Geçersiz Qdrant URL'si",
+ "invalidOllamaUrl": "Geçersiz Ollama URL'si",
+ "invalidBaseUrl": "Geçersiz temel URL'si",
+ "qdrantUrlRequired": "Qdrant URL'si gereklidir",
+ "openaiApiKeyRequired": "OpenAI API anahtarı gereklidir",
+ "modelSelectionRequired": "Model seçimi gereklidir",
+ "apiKeyRequired": "API anahtarı gereklidir",
+ "modelIdRequired": "Model kimliği gereklidir",
+ "modelDimensionRequired": "Model boyutu gereklidir",
+ "geminiApiKeyRequired": "Gemini API anahtarı gereklidir",
+ "ollamaBaseUrlRequired": "Ollama temel URL'si gereklidir",
+ "baseUrlRequired": "Temel URL'si gereklidir",
+ "modelDimensionMinValue": "Model boyutu 0'dan büyük olmalıdır"
+ },
"advancedConfigLabel": "Gelişmiş Yapılandırma",
"searchMinScoreLabel": "Arama Skoru Eşiği",
"searchMinScoreDescription": "Arama sonuçları için gereken minimum benzerlik puanı (0.0-1.0). Düşük değerler daha fazla sonuç döndürür ancak daha az alakalı olabilir. Yüksek değerler daha az ancak daha alakalı sonuçlar döndürür.",
@@ -191,6 +206,8 @@
"createProfile": "Profil oluştur",
"cannotDeleteOnlyProfile": "Yalnızca tek profili silemezsiniz",
"searchPlaceholder": "Profilleri ara",
+ "searchProviderPlaceholder": "Sağlayıcıları ara",
+ "noProviderMatchFound": "Eşleşen sağlayıcı bulunamadı",
"noMatchFound": "Eşleşen profil bulunamadı",
"vscodeLmDescription": "VS Code Dil Modeli API'si, diğer VS Code uzantıları tarafından sağlanan modelleri çalıştırmanıza olanak tanır (GitHub Copilot dahil ancak bunlarla sınırlı değildir). Başlamanın en kolay yolu, VS Code Marketplace'ten Copilot ve Copilot Chat uzantılarını yüklemektir.",
"awsCustomArnUse": "Kullanmak istediğiniz model için geçerli bir Amazon Bedrock ARN'si girin. Format örnekleri:",
diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json
index eb7cdc2306..574df08da1 100644
--- a/webview-ui/src/i18n/locales/vi/chat.json
+++ b/webview-ui/src/i18n/locales/vi/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} Đã phát hành",
"description": "Roo Code {{version}} mang đến các tính năng mạnh mẽ mới và cải tiến đáng kể để nâng cao quy trình phát triển của bạn.",
"whatsNew": "Có gì mới",
- "feature1": "Chia sẻ Nhiệm vụ 1-Click: Chia sẻ nhiệm vụ của bạn với đồng nghiệp và cộng đồng ngay lập tức chỉ với một cú nhấp chuột.",
- "feature2": "Hỗ trợ Thư mục .roo Toàn cục: Tải quy tắc và cấu hình từ thư mục .roo toàn cục để có cài đặt nhất quán giữa các dự án.",
+ "feature1": "Lập chỉ mục Codebase Tốt nghiệp từ Thử nghiệm: Lập chỉ mục codebase đầy đủ hiện đã ổn định và sẵn sàng cho sử dụng sản xuất với tìm kiếm cải tiến và hiểu biết ngữ cảnh.",
+ "feature2": "Tính năng Danh sách Todo Mới: Giữ nhiệm vụ của bạn đúng hướng với quản lý todo tích hợp giúp bạn duy trì tổ chức và tập trung vào mục tiêu phát triển.",
"feature3": "Cải thiện Chuyển đổi từ Architect sang Code: Chuyển đổi mượt mà từ lập kế hoạch trong chế độ Architect sang triển khai trong chế độ Code.",
"hideButton": "Ẩn thông báo",
"detailsDiscussLinks": "Nhận thêm chi tiết và thảo luận tại Discord và Reddit 🚀"
diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json
index 3c9aad3d9f..e31355b403 100644
--- a/webview-ui/src/i18n/locales/vi/settings.json
+++ b/webview-ui/src/i18n/locales/vi/settings.json
@@ -98,6 +98,21 @@
"error": "Lỗi"
},
"close": "Đóng",
+ "validation": {
+ "invalidQdrantUrl": "URL Qdrant không hợp lệ",
+ "invalidOllamaUrl": "URL Ollama không hợp lệ",
+ "invalidBaseUrl": "URL cơ sở không hợp lệ",
+ "qdrantUrlRequired": "Yêu cầu URL Qdrant",
+ "openaiApiKeyRequired": "Yêu cầu khóa API OpenAI",
+ "modelSelectionRequired": "Yêu cầu chọn mô hình",
+ "apiKeyRequired": "Yêu cầu khóa API",
+ "modelIdRequired": "Yêu cầu ID mô hình",
+ "modelDimensionRequired": "Yêu cầu kích thước mô hình",
+ "geminiApiKeyRequired": "Yêu cầu khóa API Gemini",
+ "ollamaBaseUrlRequired": "Yêu cầu URL cơ sở Ollama",
+ "baseUrlRequired": "Yêu cầu URL cơ sở",
+ "modelDimensionMinValue": "Kích thước mô hình phải lớn hơn 0"
+ },
"advancedConfigLabel": "Cấu hình nâng cao",
"searchMinScoreLabel": "Ngưỡng điểm tìm kiếm",
"searchMinScoreDescription": "Điểm tương đồng tối thiểu (0.0-1.0) cần thiết cho kết quả tìm kiếm. Giá trị thấp hơn trả về nhiều kết quả hơn nhưng có thể kém liên quan hơn. Giá trị cao hơn trả về ít kết quả hơn nhưng có liên quan hơn.",
@@ -191,6 +206,8 @@
"createProfile": "Tạo hồ sơ",
"cannotDeleteOnlyProfile": "Không thể xóa hồ sơ duy nhất",
"searchPlaceholder": "Tìm kiếm hồ sơ",
+ "searchProviderPlaceholder": "Tìm kiếm nhà cung cấp",
+ "noProviderMatchFound": "Không tìm thấy nhà cung cấp",
"noMatchFound": "Không tìm thấy hồ sơ phù hợp",
"vscodeLmDescription": "API Mô hình Ngôn ngữ VS Code cho phép bạn chạy các mô hình được cung cấp bởi các tiện ích mở rộng khác của VS Code (bao gồm nhưng không giới hạn ở GitHub Copilot). Cách dễ nhất để bắt đầu là cài đặt các tiện ích mở rộng Copilot và Copilot Chat từ VS Code Marketplace.",
"awsCustomArnUse": "Nhập một ARN Amazon Bedrock hợp lệ cho mô hình bạn muốn sử dụng. Ví dụ về định dạng:",
diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json
index 93494e6f50..f6e51cfa49 100644
--- a/webview-ui/src/i18n/locales/zh-CN/chat.json
+++ b/webview-ui/src/i18n/locales/zh-CN/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} 已发布",
"description": "Roo Code {{version}} 带来强大的新功能和重大改进,提升您的开发工作流程。",
"whatsNew": "新特性",
- "feature1": "一键任务分享: 一键即可与同事和社区分享您的任务。",
- "feature2": "全局 .roo 目录支持: 从全局 .roo 目录加载规则和配置,确保项目间设置一致。",
+ "feature1": "代码库索引从实验阶段正式发布: 完整的代码库索引现已稳定,可用于生产环境,具备改进的搜索和上下文理解功能。",
+ "feature2": "新增待办事项列表功能: 通过集成的待办事项管理保持任务进度,帮助你保持条理并专注于开发目标。",
"feature3": "改进的架构师到代码转换: 从架构师模式的规划到代码模式的实现,实现无缝交接。",
"hideButton": "隐藏公告",
"detailsDiscussLinks": "在 Discord 和 Reddit 获取更多详情并参与讨论 🚀"
diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json
index 4e90ec3771..4b46b9af0a 100644
--- a/webview-ui/src/i18n/locales/zh-CN/settings.json
+++ b/webview-ui/src/i18n/locales/zh-CN/settings.json
@@ -98,6 +98,21 @@
"error": "错误"
},
"close": "关闭",
+ "validation": {
+ "invalidQdrantUrl": "无效的 Qdrant URL",
+ "invalidOllamaUrl": "无效的 Ollama URL",
+ "invalidBaseUrl": "无效的基础 URL",
+ "qdrantUrlRequired": "需要 Qdrant URL",
+ "openaiApiKeyRequired": "需要 OpenAI API 密钥",
+ "modelSelectionRequired": "需要选择模型",
+ "apiKeyRequired": "需要 API 密钥",
+ "modelIdRequired": "需要模型 ID",
+ "modelDimensionRequired": "需要模型维度",
+ "geminiApiKeyRequired": "需要 Gemini API 密钥",
+ "ollamaBaseUrlRequired": "需要 Ollama 基础 URL",
+ "baseUrlRequired": "需要基础 URL",
+ "modelDimensionMinValue": "模型维度必须大于 0"
+ },
"advancedConfigLabel": "高级配置",
"searchMinScoreLabel": "搜索分数阈值",
"searchMinScoreDescription": "搜索结果所需的最低相似度分数(0.0-1.0)。较低的值返回更多结果,但可能不太相关。较高的值返回较少但更相关的结果。",
@@ -191,6 +206,8 @@
"createProfile": "创建配置",
"cannotDeleteOnlyProfile": "无法删除唯一的配置文件",
"searchPlaceholder": "搜索配置文件",
+ "searchProviderPlaceholder": "搜索提供商",
+ "noProviderMatchFound": "未找到提供商",
"noMatchFound": "未找到匹配的配置文件",
"vscodeLmDescription": "VS Code 语言模型 API 允许您运行由其他 VS Code 扩展(包括但不限于 GitHub Copilot)提供的模型。最简单的方法是从 VS Code 市场安装 Copilot 和 Copilot Chat 扩展。",
"awsCustomArnUse": "请输入有效的 Amazon Bedrock ARN(Amazon资源名称),格式示例:",
diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json
index e7a476cb37..54aeacf15c 100644
--- a/webview-ui/src/i18n/locales/zh-TW/chat.json
+++ b/webview-ui/src/i18n/locales/zh-TW/chat.json
@@ -242,8 +242,8 @@
"title": "🎉 Roo Code {{version}} 已發布",
"description": "Roo Code {{version}} 帶來強大的新功能和重大改進,提升您的開發工作流程。",
"whatsNew": "新功能",
- "feature1": "一鍵分享工作:只需一鍵即可立即與同事和社群分享您的工作。",
- "feature2": "全域 .roo 目錄支援:從全域 .roo 目錄載入規則和設定,確保專案間設定一致。",
+ "feature1": "程式碼庫索引從實驗階段正式發布:完整的程式碼庫索引現已穩定,可用於正式環境,具備改進的搜尋和內容理解功能。",
+ "feature2": "新增待辦事項清單功能:透過整合的待辦事項管理保持工作進度,幫助您保持條理並專注於開發目標。",
"feature3": "改進的 Architect 到 Code 轉換:從 Architect 模式的規劃到 Code 模式的實作,轉換更加順暢。",
"hideButton": "隱藏公告",
"detailsDiscussLinks": "在 Discord 和 Reddit 取得更多詳細資訊並參與討論 🚀"
diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json
index 5d55596e3d..3e35097b1e 100644
--- a/webview-ui/src/i18n/locales/zh-TW/settings.json
+++ b/webview-ui/src/i18n/locales/zh-TW/settings.json
@@ -98,6 +98,21 @@
"error": "錯誤"
},
"close": "關閉",
+ "validation": {
+ "invalidQdrantUrl": "無效的 Qdrant URL",
+ "invalidOllamaUrl": "無效的 Ollama URL",
+ "invalidBaseUrl": "無效的基礎 URL",
+ "qdrantUrlRequired": "需要 Qdrant URL",
+ "openaiApiKeyRequired": "需要 OpenAI API 金鑰",
+ "modelSelectionRequired": "需要選擇模型",
+ "apiKeyRequired": "需要 API 金鑰",
+ "modelIdRequired": "需要模型 ID",
+ "modelDimensionRequired": "需要模型維度",
+ "geminiApiKeyRequired": "需要 Gemini API 金鑰",
+ "ollamaBaseUrlRequired": "需要 Ollama 基礎 URL",
+ "baseUrlRequired": "需要基礎 URL",
+ "modelDimensionMinValue": "模型維度必須大於 0"
+ },
"advancedConfigLabel": "進階設定",
"searchMinScoreLabel": "搜尋分數閾值",
"searchMinScoreDescription": "搜尋結果所需的最低相似度分數(0.0-1.0)。較低的值會傳回更多結果,但可能較不相關。較高的值會傳回較少但更相關的結果。",
@@ -191,6 +206,8 @@
"createProfile": "建立設定檔",
"cannotDeleteOnlyProfile": "無法刪除唯一的設定檔",
"searchPlaceholder": "搜尋設定檔",
+ "searchProviderPlaceholder": "搜尋供應商",
+ "noProviderMatchFound": "找不到供應商",
"noMatchFound": "找不到符合的設定檔",
"vscodeLmDescription": "VS Code 語言模型 API 可以讓您使用其他擴充功能(如 GitHub Copilot)提供的模型。最簡單的方式是從 VS Code Marketplace 安裝 Copilot 和 Copilot Chat 擴充套件。",
"awsCustomArnUse": "輸入您要使用的模型的有效 Amazon Bedrock ARN。格式範例:",