Browse Source

Chat index UI enhancements (#5451)

Co-authored-by: Daniel Riccio <[email protected]>
Murilo Pires 5 months ago
parent
commit
150d71256f

+ 25 - 30
webview-ui/src/components/chat/ChatTextArea.tsx

@@ -943,10 +943,11 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 									"resize-none",
 									"overflow-x-hidden",
 									"overflow-y-auto",
-									"pr-2",
+									"pr-9",
 									"flex-none flex-grow",
 									"z-[2]",
 									"scrollbar-none",
+									"scrollbar-hide",
 								)}
 								onScroll={() => updateHighlights()}
 							/>
@@ -961,24 +962,31 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 								</Button>
 							)}
 
+							<div className="absolute top-1 right-1 z-30">
+								<IconButton
+									iconClass={isEnhancingPrompt ? "codicon-loading" : "codicon-sparkle"}
+									title={t("chat:enhancePrompt")}
+									disabled={sendingDisabled}
+									isLoading={isEnhancingPrompt}
+									onClick={handleEnhancePrompt}
+									className="opacity-60 hover:opacity-100 text-vscode-descriptionForeground hover:text-vscode-foreground"
+								/>
+							</div>
+
+							<div className="absolute bottom-1 right-1 z-30">
+								<IconButton
+									iconClass="codicon-send"
+									title={t("chat:sendMessage")}
+									disabled={sendingDisabled}
+									onClick={onSend}
+									className="opacity-60 hover:opacity-100 text-vscode-descriptionForeground hover:text-vscode-foreground"
+								/>
+							</div>
+
 							{!inputValue && (
 								<div
-									className={cn(
-										"absolute",
-										"left-2",
-										"flex",
-										"gap-2",
-										"text-xs",
-										"text-descriptionForeground",
-										"pointer-events-none",
-										"z-25",
-										"bottom-1.5",
-										"pr-2",
-										"transition-opacity",
-										"duration-200",
-										"ease-in-out",
-										"opacity-70",
-									)}>
+									className="absolute left-2 z-30 pr-9 flex items-center h-8"
+									style={{ bottom: "0.25rem", color: "var(--vscode-tab-inactiveForeground)" }}>
 									{placeholderBottomText}
 								</div>
 							)}
@@ -1134,25 +1142,12 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
 
 					<div className={cn("flex", "items-center", "gap-0.5", "shrink-0")}>
 						{codebaseIndexConfig?.codebaseIndexEnabled && <IndexingStatusDot />}
-						<IconButton
-							iconClass={isEnhancingPrompt ? "codicon-loading" : "codicon-sparkle"}
-							title={t("chat:enhancePrompt")}
-							disabled={sendingDisabled}
-							isLoading={isEnhancingPrompt}
-							onClick={handleEnhancePrompt}
-						/>
 						<IconButton
 							iconClass="codicon-device-camera"
 							title={t("chat:addImages")}
 							disabled={shouldDisableImages}
 							onClick={onSelectImages}
 						/>
-						<IconButton
-							iconClass="codicon-send"
-							title={t("chat:sendMessage")}
-							disabled={sendingDisabled}
-							onClick={onSend}
-						/>
 					</div>
 				</div>
 			</div>

+ 300 - 231
webview-ui/src/components/chat/CodeIndexPopover.tsx

@@ -72,6 +72,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
 	const { codebaseIndexConfig, codebaseIndexModels } = useExtensionState()
 	const [open, setOpen] = useState(false)
 	const [isAdvancedSettingsOpen, setIsAdvancedSettingsOpen] = useState(false)
+	const [isSetupSettingsOpen, setIsSetupSettingsOpen] = useState(false)
 
 	const [indexingStatus, setIndexingStatus] = useState<IndexingStatus>(externalIndexingStatus)
 
@@ -304,7 +305,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
 		<Popover open={open} onOpenChange={setOpen}>
 			<PopoverTrigger asChild>{children}</PopoverTrigger>
 			<PopoverContent
-				className="w-[calc(100vw-32px)] max-w-[450px] max-h-[80vh] overflow-y-auto p-4"
+				className="w-[calc(100vw-32px)] max-w-[450px] max-h-[80vh] overflow-y-auto p-0"
 				align="end"
 				alignOffset={0}
 				side="bottom"
@@ -312,9 +313,11 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
 				collisionPadding={16}
 				avoidCollisions={true}
 				container={portalContainer}>
-				<div className="mb-4">
-					<h3 className="text-base font-medium mb-2">{t("settings:codeIndex.title")}</h3>
-					<p className="text-sm text-vscode-descriptionForeground">
+				<div className="p-3 border-b border-vscode-dropdown-border cursor-default">
+					<div className="flex flex-row items-center gap-1 p-0 mt-0 mb-1 w-full">
+						<h4 className="m-0 pb-2 flex-1">{t("settings:codeIndex.title")}</h4>
+					</div>
+					<p className="my-0 pr-4 text-sm w-full">
 						<Trans i18nKey="settings:codeIndex.description">
 							<VSCodeLink
 								href={buildDocLink("features/experimental/codebase-indexing", "settings")}
@@ -324,7 +327,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
 					</p>
 				</div>
 
-				<div className="space-y-4">
+				<div className="p-4">
 					{/* Status Section */}
 					<div className="space-y-2">
 						<h4 className="text-sm font-medium">{t("settings:codeIndex.statusTitle")}</h4>
@@ -357,233 +360,297 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
 						)}
 					</div>
 
-					{/* Embedder Provider Section */}
-					<div className="space-y-2">
-						<label className="text-sm font-medium">{t("settings:codeIndex.embedderProviderLabel")}</label>
-						<Select
-							value={currentSettings.codebaseIndexEmbedderProvider}
-							onValueChange={(value: EmbedderProvider) =>
-								updateSetting("codebaseIndexEmbedderProvider", value)
-							}>
-							<SelectTrigger className="w-full">
-								<SelectValue />
-							</SelectTrigger>
-							<SelectContent>
-								<SelectItem value="openai">{t("settings:codeIndex.openaiProvider")}</SelectItem>
-								<SelectItem value="ollama">{t("settings:codeIndex.ollamaProvider")}</SelectItem>
-								<SelectItem value="openai-compatible">
-									{t("settings:codeIndex.openaiCompatibleProvider")}
-								</SelectItem>
-								<SelectItem value="gemini">{t("settings:codeIndex.geminiProvider")}</SelectItem>
-							</SelectContent>
-						</Select>
-					</div>
-
-					{/* Provider-specific settings */}
-					{currentSettings.codebaseIndexEmbedderProvider === "openai" && (
-						<>
-							<div className="space-y-2">
-								<label className="text-sm font-medium">{t("settings:codeIndex.openAiKeyLabel")}</label>
-								<VSCodeTextField
-									type="password"
-									value={currentSettings.codeIndexOpenAiKey || ""}
-									onInput={(e: any) => updateSetting("codeIndexOpenAiKey", e.target.value)}
-									placeholder={t("settings:codeIndex.openAiKeyPlaceholder")}
-									className="w-full"
-								/>
-							</div>
-
-							<div className="space-y-2">
-								<label className="text-sm font-medium">{t("settings:codeIndex.modelLabel")}</label>
-								<VSCodeDropdown
-									value={currentSettings.codebaseIndexEmbedderModelId}
-									onChange={(e: any) => updateSetting("codebaseIndexEmbedderModelId", e.target.value)}
-									className="w-full">
-									<VSCodeOption value="">{t("settings:codeIndex.selectModel")}</VSCodeOption>
-									{getAvailableModels().map((modelId) => {
-										const model =
-											codebaseIndexModels?.[currentSettings.codebaseIndexEmbedderProvider]?.[
-												modelId
-											]
-										return (
-											<VSCodeOption key={modelId} value={modelId}>
-												{modelId}{" "}
-												{model
-													? t("settings:codeIndex.modelDimensions", {
-															dimension: model.dimension,
-														})
-													: ""}
-											</VSCodeOption>
-										)
-									})}
-								</VSCodeDropdown>
-							</div>
-						</>
-					)}
-
-					{currentSettings.codebaseIndexEmbedderProvider === "ollama" && (
-						<>
-							<div className="space-y-2">
-								<label className="text-sm font-medium">
-									{t("settings:codeIndex.ollamaBaseUrlLabel")}
-								</label>
-								<VSCodeTextField
-									value={currentSettings.codebaseIndexEmbedderBaseUrl || ""}
-									onInput={(e: any) => updateSetting("codebaseIndexEmbedderBaseUrl", e.target.value)}
-									placeholder={t("settings:codeIndex.ollamaUrlPlaceholder")}
-									className="w-full"
-								/>
-							</div>
-
-							<div className="space-y-2">
-								<label className="text-sm font-medium">{t("settings:codeIndex.modelLabel")}</label>
-								<VSCodeDropdown
-									value={currentSettings.codebaseIndexEmbedderModelId}
-									onChange={(e: any) => updateSetting("codebaseIndexEmbedderModelId", e.target.value)}
-									className="w-full">
-									<VSCodeOption value="">{t("settings:codeIndex.selectModel")}</VSCodeOption>
-									{getAvailableModels().map((modelId) => {
-										const model =
-											codebaseIndexModels?.[currentSettings.codebaseIndexEmbedderProvider]?.[
-												modelId
-											]
-										return (
-											<VSCodeOption key={modelId} value={modelId}>
-												{modelId}{" "}
-												{model
-													? t("settings:codeIndex.modelDimensions", {
-															dimension: model.dimension,
-														})
-													: ""}
-											</VSCodeOption>
-										)
-									})}
-								</VSCodeDropdown>
-							</div>
-						</>
-					)}
-
-					{currentSettings.codebaseIndexEmbedderProvider === "openai-compatible" && (
-						<>
-							<div className="space-y-2">
-								<label className="text-sm font-medium">
-									{t("settings:codeIndex.openAiCompatibleBaseUrlLabel")}
-								</label>
-								<VSCodeTextField
-									value={currentSettings.codebaseIndexOpenAiCompatibleBaseUrl || ""}
-									onInput={(e: any) =>
-										updateSetting("codebaseIndexOpenAiCompatibleBaseUrl", e.target.value)
-									}
-									placeholder={t("settings:codeIndex.openAiCompatibleBaseUrlPlaceholder")}
-									className="w-full"
-								/>
-							</div>
-
-							<div className="space-y-2">
-								<label className="text-sm font-medium">
-									{t("settings:codeIndex.openAiCompatibleApiKeyLabel")}
-								</label>
-								<VSCodeTextField
-									type="password"
-									value={currentSettings.codebaseIndexOpenAiCompatibleApiKey || ""}
-									onInput={(e: any) =>
-										updateSetting("codebaseIndexOpenAiCompatibleApiKey", e.target.value)
-									}
-									placeholder={t("settings:codeIndex.openAiCompatibleApiKeyPlaceholder")}
-									className="w-full"
-								/>
-							</div>
-
-							<div className="space-y-2">
-								<label className="text-sm font-medium">{t("settings:codeIndex.modelLabel")}</label>
-								<VSCodeTextField
-									value={currentSettings.codebaseIndexEmbedderModelId || ""}
-									onInput={(e: any) => updateSetting("codebaseIndexEmbedderModelId", e.target.value)}
-									placeholder={t("settings:codeIndex.modelPlaceholder")}
-									className="w-full"
-								/>
-							</div>
+					{/* Setup Settings Disclosure */}
+					<div className="mt-4">
+						<button
+							onClick={() => setIsSetupSettingsOpen(!isSetupSettingsOpen)}
+							className="flex items-center text-xs text-vscode-foreground hover:text-vscode-textLink-foreground focus:outline-none"
+							aria-expanded={isSetupSettingsOpen}>
+							<span
+								className={`codicon codicon-${isSetupSettingsOpen ? "chevron-down" : "chevron-right"} mr-1`}></span>
+							<span className="text-base font-semibold">{t("settings:codeIndex.setupConfigLabel")}</span>
+						</button>
 
-							<div className="space-y-2">
-								<label className="text-sm font-medium">
-									{t("settings:codeIndex.modelDimensionLabel")}
-								</label>
-								<VSCodeTextField
-									value={currentSettings.codebaseIndexEmbedderModelDimension?.toString() || ""}
-									onInput={(e: any) => {
-										const value = e.target.value ? parseInt(e.target.value) : undefined
-										updateSetting("codebaseIndexEmbedderModelDimension", value)
-									}}
-									placeholder={t("settings:codeIndex.modelDimensionPlaceholder")}
-									className="w-full"
-								/>
-							</div>
-						</>
-					)}
+						{isSetupSettingsOpen && (
+							<div className="mt-4 space-y-4">
+								{/* Embedder Provider Section */}
+								<div className="space-y-2">
+									<label className="text-sm font-medium">
+										{t("settings:codeIndex.embedderProviderLabel")}
+									</label>
+									<Select
+										value={currentSettings.codebaseIndexEmbedderProvider}
+										onValueChange={(value: EmbedderProvider) =>
+											updateSetting("codebaseIndexEmbedderProvider", value)
+										}>
+										<SelectTrigger className="w-full">
+											<SelectValue />
+										</SelectTrigger>
+										<SelectContent>
+											<SelectItem value="openai">
+												{t("settings:codeIndex.openaiProvider")}
+											</SelectItem>
+											<SelectItem value="ollama">
+												{t("settings:codeIndex.ollamaProvider")}
+											</SelectItem>
+											<SelectItem value="openai-compatible">
+												{t("settings:codeIndex.openaiCompatibleProvider")}
+											</SelectItem>
+											<SelectItem value="gemini">
+												{t("settings:codeIndex.geminiProvider")}
+											</SelectItem>
+										</SelectContent>
+									</Select>
+								</div>
 
-					{currentSettings.codebaseIndexEmbedderProvider === "gemini" && (
-						<>
-							<div className="space-y-2">
-								<label className="text-sm font-medium">
-									{t("settings:codeIndex.geminiApiKeyLabel")}
-								</label>
-								<VSCodeTextField
-									type="password"
-									value={currentSettings.codebaseIndexGeminiApiKey || ""}
-									onInput={(e: any) => updateSetting("codebaseIndexGeminiApiKey", e.target.value)}
-									placeholder={t("settings:codeIndex.geminiApiKeyPlaceholder")}
-									className="w-full"
-								/>
-							</div>
+								{/* Provider-specific settings */}
+								{currentSettings.codebaseIndexEmbedderProvider === "openai" && (
+									<>
+										<div className="space-y-2">
+											<label className="text-sm font-medium">
+												{t("settings:codeIndex.openAiKeyLabel")}
+											</label>
+											<VSCodeTextField
+												type="password"
+												value={currentSettings.codeIndexOpenAiKey || ""}
+												onInput={(e: any) =>
+													updateSetting("codeIndexOpenAiKey", e.target.value)
+												}
+												placeholder={t("settings:codeIndex.openAiKeyPlaceholder")}
+												className="w-full"
+											/>
+										</div>
+
+										<div className="space-y-2">
+											<label className="text-sm font-medium">
+												{t("settings:codeIndex.modelLabel")}
+											</label>
+											<VSCodeDropdown
+												value={currentSettings.codebaseIndexEmbedderModelId}
+												onChange={(e: any) =>
+													updateSetting("codebaseIndexEmbedderModelId", e.target.value)
+												}
+												className="w-full">
+												<VSCodeOption value="">
+													{t("settings:codeIndex.selectModel")}
+												</VSCodeOption>
+												{getAvailableModels().map((modelId) => {
+													const model =
+														codebaseIndexModels?.[
+															currentSettings.codebaseIndexEmbedderProvider
+														]?.[modelId]
+													return (
+														<VSCodeOption key={modelId} value={modelId}>
+															{modelId}{" "}
+															{model
+																? t("settings:codeIndex.modelDimensions", {
+																		dimension: model.dimension,
+																	})
+																: ""}
+														</VSCodeOption>
+													)
+												})}
+											</VSCodeDropdown>
+										</div>
+									</>
+								)}
+
+								{currentSettings.codebaseIndexEmbedderProvider === "ollama" && (
+									<>
+										<div className="space-y-2">
+											<label className="text-sm font-medium">
+												{t("settings:codeIndex.ollamaBaseUrlLabel")}
+											</label>
+											<VSCodeTextField
+												value={currentSettings.codebaseIndexEmbedderBaseUrl || ""}
+												onInput={(e: any) =>
+													updateSetting("codebaseIndexEmbedderBaseUrl", e.target.value)
+												}
+												placeholder={t("settings:codeIndex.ollamaUrlPlaceholder")}
+												className="w-full"
+											/>
+										</div>
+
+										<div className="space-y-2">
+											<label className="text-sm font-medium">
+												{t("settings:codeIndex.modelLabel")}
+											</label>
+											<VSCodeDropdown
+												value={currentSettings.codebaseIndexEmbedderModelId}
+												onChange={(e: any) =>
+													updateSetting("codebaseIndexEmbedderModelId", e.target.value)
+												}
+												className="w-full">
+												<VSCodeOption value="">
+													{t("settings:codeIndex.selectModel")}
+												</VSCodeOption>
+												{getAvailableModels().map((modelId) => {
+													const model =
+														codebaseIndexModels?.[
+															currentSettings.codebaseIndexEmbedderProvider
+														]?.[modelId]
+													return (
+														<VSCodeOption key={modelId} value={modelId}>
+															{modelId}{" "}
+															{model
+																? t("settings:codeIndex.modelDimensions", {
+																		dimension: model.dimension,
+																	})
+																: ""}
+														</VSCodeOption>
+													)
+												})}
+											</VSCodeDropdown>
+										</div>
+									</>
+								)}
+
+								{currentSettings.codebaseIndexEmbedderProvider === "openai-compatible" && (
+									<>
+										<div className="space-y-2">
+											<label className="text-sm font-medium">
+												{t("settings:codeIndex.openAiCompatibleBaseUrlLabel")}
+											</label>
+											<VSCodeTextField
+												value={currentSettings.codebaseIndexOpenAiCompatibleBaseUrl || ""}
+												onInput={(e: any) =>
+													updateSetting(
+														"codebaseIndexOpenAiCompatibleBaseUrl",
+														e.target.value,
+													)
+												}
+												placeholder={t("settings:codeIndex.openAiCompatibleBaseUrlPlaceholder")}
+												className="w-full"
+											/>
+										</div>
+
+										<div className="space-y-2">
+											<label className="text-sm font-medium">
+												{t("settings:codeIndex.openAiCompatibleApiKeyLabel")}
+											</label>
+											<VSCodeTextField
+												type="password"
+												value={currentSettings.codebaseIndexOpenAiCompatibleApiKey || ""}
+												onInput={(e: any) =>
+													updateSetting("codebaseIndexOpenAiCompatibleApiKey", e.target.value)
+												}
+												placeholder={t("settings:codeIndex.openAiCompatibleApiKeyPlaceholder")}
+												className="w-full"
+											/>
+										</div>
+
+										<div className="space-y-2">
+											<label className="text-sm font-medium">
+												{t("settings:codeIndex.modelLabel")}
+											</label>
+											<VSCodeTextField
+												value={currentSettings.codebaseIndexEmbedderModelId || ""}
+												onInput={(e: any) =>
+													updateSetting("codebaseIndexEmbedderModelId", e.target.value)
+												}
+												placeholder={t("settings:codeIndex.modelPlaceholder")}
+												className="w-full"
+											/>
+										</div>
+
+										<div className="space-y-2">
+											<label className="text-sm font-medium">
+												{t("settings:codeIndex.modelDimensionLabel")}
+											</label>
+											<VSCodeTextField
+												value={
+													currentSettings.codebaseIndexEmbedderModelDimension?.toString() ||
+													""
+												}
+												onInput={(e: any) => {
+													const value = e.target.value ? parseInt(e.target.value) : undefined
+													updateSetting("codebaseIndexEmbedderModelDimension", value)
+												}}
+												placeholder={t("settings:codeIndex.modelDimensionPlaceholder")}
+												className="w-full"
+											/>
+										</div>
+									</>
+								)}
+
+								{currentSettings.codebaseIndexEmbedderProvider === "gemini" && (
+									<>
+										<div className="space-y-2">
+											<label className="text-sm font-medium">
+												{t("settings:codeIndex.geminiApiKeyLabel")}
+											</label>
+											<VSCodeTextField
+												type="password"
+												value={currentSettings.codebaseIndexGeminiApiKey || ""}
+												onInput={(e: any) =>
+													updateSetting("codebaseIndexGeminiApiKey", e.target.value)
+												}
+												placeholder={t("settings:codeIndex.geminiApiKeyPlaceholder")}
+												className="w-full"
+											/>
+										</div>
+
+										<div className="space-y-2">
+											<label className="text-sm font-medium">
+												{t("settings:codeIndex.modelLabel")}
+											</label>
+											<VSCodeDropdown
+												value={currentSettings.codebaseIndexEmbedderModelId}
+												onChange={(e: any) =>
+													updateSetting("codebaseIndexEmbedderModelId", e.target.value)
+												}
+												className="w-full">
+												<VSCodeOption value="">
+													{t("settings:codeIndex.selectModel")}
+												</VSCodeOption>
+												{getAvailableModels().map((modelId) => {
+													const model =
+														codebaseIndexModels?.[
+															currentSettings.codebaseIndexEmbedderProvider
+														]?.[modelId]
+													return (
+														<VSCodeOption key={modelId} value={modelId}>
+															{modelId}{" "}
+															{model
+																? t("settings:codeIndex.modelDimensions", {
+																		dimension: model.dimension,
+																	})
+																: ""}
+														</VSCodeOption>
+													)
+												})}
+											</VSCodeDropdown>
+										</div>
+									</>
+								)}
+
+								{/* Qdrant Settings */}
+								<div className="space-y-2">
+									<label className="text-sm font-medium">
+										{t("settings:codeIndex.qdrantUrlLabel")}
+									</label>
+									<VSCodeTextField
+										value={currentSettings.codebaseIndexQdrantUrl || ""}
+										onInput={(e: any) => updateSetting("codebaseIndexQdrantUrl", e.target.value)}
+										placeholder={t("settings:codeIndex.qdrantUrlPlaceholder")}
+										className="w-full"
+									/>
+								</div>
 
-							<div className="space-y-2">
-								<label className="text-sm font-medium">{t("settings:codeIndex.modelLabel")}</label>
-								<VSCodeDropdown
-									value={currentSettings.codebaseIndexEmbedderModelId}
-									onChange={(e: any) => updateSetting("codebaseIndexEmbedderModelId", e.target.value)}
-									className="w-full">
-									<VSCodeOption value="">{t("settings:codeIndex.selectModel")}</VSCodeOption>
-									{getAvailableModels().map((modelId) => {
-										const model =
-											codebaseIndexModels?.[currentSettings.codebaseIndexEmbedderProvider]?.[
-												modelId
-											]
-										return (
-											<VSCodeOption key={modelId} value={modelId}>
-												{modelId}{" "}
-												{model
-													? t("settings:codeIndex.modelDimensions", {
-															dimension: model.dimension,
-														})
-													: ""}
-											</VSCodeOption>
-										)
-									})}
-								</VSCodeDropdown>
+								<div className="space-y-2">
+									<label className="text-sm font-medium">
+										{t("settings:codeIndex.qdrantApiKeyLabel")}
+									</label>
+									<VSCodeTextField
+										type="password"
+										value={currentSettings.codeIndexQdrantApiKey || ""}
+										onInput={(e: any) => updateSetting("codeIndexQdrantApiKey", e.target.value)}
+										placeholder={t("settings:codeIndex.qdrantApiKeyPlaceholder")}
+										className="w-full"
+									/>
+								</div>
 							</div>
-						</>
-					)}
-
-					{/* Qdrant Settings */}
-					<div className="space-y-2">
-						<label className="text-sm font-medium">{t("settings:codeIndex.qdrantUrlLabel")}</label>
-						<VSCodeTextField
-							value={currentSettings.codebaseIndexQdrantUrl || ""}
-							onInput={(e: any) => updateSetting("codebaseIndexQdrantUrl", e.target.value)}
-							placeholder={t("settings:codeIndex.qdrantUrlPlaceholder")}
-							className="w-full"
-						/>
-					</div>
-
-					<div className="space-y-2">
-						<label className="text-sm font-medium">{t("settings:codeIndex.qdrantApiKeyLabel")}</label>
-						<VSCodeTextField
-							type="password"
-							value={currentSettings.codeIndexQdrantApiKey || ""}
-							onInput={(e: any) => updateSetting("codeIndexQdrantApiKey", e.target.value)}
-							placeholder={t("settings:codeIndex.qdrantApiKeyPlaceholder")}
-							className="w-full"
-						/>
+						)}
 					</div>
 
 					{/* Advanced Settings Disclosure */}
@@ -594,11 +661,13 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
 							aria-expanded={isAdvancedSettingsOpen}>
 							<span
 								className={`codicon codicon-${isAdvancedSettingsOpen ? "chevron-down" : "chevron-right"} mr-1`}></span>
-							<span>{t("settings:codeIndex.advancedConfigLabel")}</span>
+							<span className="text-base font-semibold">
+								{t("settings:codeIndex.advancedConfigLabel")}
+							</span>
 						</button>
 
 						{isAdvancedSettingsOpen && (
-							<div className="mt-4 space-y-4 pl-4">
+							<div className="mt-4 space-y-4">
 								{/* Search Score Threshold Slider */}
 								<div className="space-y-2">
 									<div className="flex items-center gap-2">
@@ -691,7 +760,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
 					</div>
 
 					{/* Action Buttons */}
-					<div className="flex items-center justify-between gap-2 pt-2">
+					<div className="flex items-center justify-between gap-2 pt-6">
 						<div className="flex gap-2">
 							{(indexingStatus.systemStatus === "Error" || indexingStatus.systemStatus === "Standby") && (
 								<VSCodeButton

+ 9 - 5
webview-ui/src/components/chat/IndexingStatusBadge.tsx

@@ -109,13 +109,17 @@ export const IndexingStatusDot: React.FC<IndexingStatusDotProps> = ({ className
 					onMouseEnter={handleMouseEnterButton}
 					onMouseLeave={handleMouseLeaveButton}
 					className={cn(
-						"flex items-center justify-center w-7 h-7 rounded-md",
-						"bg-transparent hover:bg-vscode-list-hoverBackground",
-						"cursor-pointer transition-all duration-200",
-						"opacity-85 hover:opacity-100 relative",
+						"relative inline-flex items-center justify-center",
+						"bg-transparent border-none p-1.5",
+						"rounded-md min-w-[28px] min-h-[28px]",
+						"opacity-85 text-vscode-foreground",
+						"transition-all duration-150",
+						"hover:opacity-100 hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]",
+						"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder",
+						"active:bg-[rgba(255,255,255,0.1)]",
+						className,
 					)}
 					aria-label={getTooltipText()}>
-					{/* Status dot */}
 					<span
 						className={cn(
 							"inline-block w-2 h-2 rounded-full relative z-10 transition-colors duration-200",

+ 1 - 0
webview-ui/src/i18n/locales/ca/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "URL base d'Ollama",
 		"qdrantApiKeyLabel": "Clau API de Qdrant",
 		"qdrantApiKeyPlaceholder": "Introduïu la vostra clau API de Qdrant (opcional)",
+		"setupConfigLabel": "Configuració",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 49 - 48
webview-ui/src/i18n/locales/de/settings.json

@@ -72,6 +72,7 @@
 		"qdrantKeyLabel": "Qdrant-Schlüssel:",
 		"qdrantApiKeyLabel": "Qdrant API-Schlüssel",
 		"qdrantApiKeyPlaceholder": "Gib deinen Qdrant API-Schlüssel ein (optional)",
+		"setupConfigLabel": "Einrichtung",
 		"startIndexingButton": "Start",
 		"clearIndexDataButton": "Index löschen",
 		"unsavedSettingsMessage": "Bitte speichere deine Einstellungen, bevor du den Indexierungsprozess startest.",
@@ -481,7 +482,7 @@
 		},
 		"commandDelay": {
 			"label": "Terminal-Befehlsverzögerung",
-			"description": "Verzögerung in Millisekunden, die nach der Befehlsausführung hinzugefügt wird. Die Standardeinstellung von 0 deaktiviert die Verzögerung vollständig. Dies kann dazu beitragen, dass die Befehlsausgabe in Terminals mit Timing-Problemen vollständig erfasst wird. In den meisten Terminals wird dies durch Setzen von `PROMPT_COMMAND='sleep N'` implementiert, und Powershell fügt `start-sleep` am Ende jedes Befehls hinzu. Ursprünglich war dies eine Lösung für VSCode-Bug#237208 und ist möglicherweise nicht mehr erforderlich. <0>Mehr erfahren</0>"
+			"description": "Verzögerung in Millisekunden, die nach der Befehlsausführung hinzugefügt wird. Die Standardeinstellung von 0 deaktiviert die Verzögerung vollständig. Dies kann dazu beitragen, dass die Befehlsausgabe in Terminals mit Timing-Problemen vollständig erfasst wird. In den meisten Terminals wird dies durch Setzen von `PROMPT_COMMAND='sleep N'` und Powershell fügt `start-sleep` am Ende jedes Befehls hinzu. Ursprünglich war dies eine Lösung für VSCode-Bug#237208 und ist möglicherweise nicht mehr erforderlich. <0>Mehr erfahren</0>"
 		},
 		"compressProgressBar": {
 			"label": "Fortschrittsbalken-Ausgabe komprimieren",
@@ -501,72 +502,72 @@
 		},
 		"zshP10k": {
 			"label": "Powerlevel10k-Integration aktivieren",
-			"description": "Wenn aktiviert, wird POWERLEVEL9K_TERM_SHELL_INTEGRATION=true gesetzt, um die Shell-Integrationsfunktionen von Powerlevel10k zu aktivieren. <0>Mehr erfahren</0>"
+			"description": "Wenn aktiviert, wird POWERLEVEL9K_INSTANT_PROMPT=quiet gesetzt, um die Powerlevel10k-Integration zu aktivieren. Dies kann die Leistung verbessern, indem der Prompt sofort angezeigt wird. <0>Mehr erfahren</0>"
 		},
 		"zdotdir": {
-			"label": "ZDOTDIR-Behandlung aktivieren",
-			"description": "Erstellt bei Aktivierung ein temporäres Verzeichnis für ZDOTDIR, um die zsh-Shell-Integration korrekt zu handhaben. Dies stellt sicher, dass die VSCode-Shell-Integration mit zsh funktioniert und dabei deine zsh-Konfiguration erhalten bleibt. <0>Mehr erfahren</0>"
+			"label": "ZDOTDIR Handhabung aktivieren",
+			"description": "Wenn aktiviert, wird ein temporäres Verzeichnis für ZDOTDIR erstellt, um die Zsh-Shell-Integration ordnungsgemäß zu handhaben. Dies stellt sicher, dass die VSCode-Shell-Integration mit Zsh korrekt funktioniert, während deine Zsh-Konfiguration erhalten bleibt. <0>Mehr erfahren</0>"
 		},
 		"inheritEnv": {
-			"label": "Umgebungsvariablen übernehmen",
-			"description": "Wenn aktiviert, übernimmt das Terminal Umgebungsvariablen vom übergeordneten VSCode-Prozess, wie z.B. in Benutzerprofilen definierte Shell-Integrationseinstellungen. Dies schaltet direkt die globale VSCode-Einstellung `terminal.integrated.inheritEnv` um. <0>Mehr erfahren</0>"
+			"label": "Umgebungsvariablen erben",
+			"description": "Wenn aktiviert, erbt das Terminal Umgebungsvariablen aus dem übergeordneten Prozess von VSCode, wie z.B. benutzerdefinierte Shell-Integrationseinstellungen. Dies schaltet direkt die globale VSCode-Einstellung `terminal.integrated.inheritEnv` um. <0>Mehr erfahren</0>"
 		}
 	},
 	"advanced": {
 		"diff": {
 			"label": "Bearbeitung durch Diffs aktivieren",
-			"description": "Wenn aktiviert, kann Roo Dateien schneller bearbeiten und lehnt automatisch gekürzte vollständige Dateischreibvorgänge ab. Funktioniert am besten mit dem neuesten Claude 3.7 Sonnet-Modell.",
+			"description": "Wenn aktiviert, kann Roo Dateien schneller bearbeiten und lehnt automatisch abgeschnittene vollständige Dateischreibvorgänge ab. Funktioniert am besten mit dem neuesten Claude 3.7 Sonnet-Modell.",
 			"strategy": {
 				"label": "Diff-Strategie",
 				"options": {
-					"standard": "Standard (Einzelner Block)",
-					"multiBlock": "Experimentell: Multi-Block-Diff",
-					"unified": "Experimentell: Vereinheitlichter Diff"
+					"standard": "Standard (Einzelblock)",
+					"multiBlock": "Experimentell: Mehrblock-Diff",
+					"unified": "Experimentell: Einheitliches Diff"
 				},
 				"descriptions": {
-					"standard": "Die Standard-Diff-Strategie wendet Änderungen auf einen einzelnen Codeblock gleichzeitig an.",
-					"unified": "Die vereinheitlichte Diff-Strategie verwendet mehrere Ansätze zum Anwenden von Diffs und wählt den besten Ansatz aus.",
-					"multiBlock": "Die Multi-Block-Diff-Strategie ermöglicht die Aktualisierung mehrerer Codeblöcke in einer Datei in einer Anfrage."
+					"standard": "Die Standard-Diff-Strategie wendet Änderungen jeweils auf einen einzelnen Codeblock an.",
+					"unified": "Die einheitliche Diff-Strategie wendet mehrere Ansätze zur Anwendung von Diffs an und wählt den besten Ansatz.",
+					"multiBlock": "Die Mehrblock-Diff-Strategie ermöglicht das Aktualisieren mehrerer Codeblöcke in einer Datei in einer Anfrage."
 				}
 			},
 			"matchPrecision": {
-				"label": "Übereinstimmungsgenauigkeit",
-				"description": "Dieser Schieberegler steuert, wie genau Codeabschnitte beim Anwenden von Diffs übereinstimmen müssen. Niedrigere Werte ermöglichen flexiblere Übereinstimmungen, erhöhen aber das Risiko falscher Ersetzungen. Verwende Werte unter 100% mit äußerster Vorsicht."
+				"label": "Übereinstimmungspräzision",
+				"description": "Dieser Schieberegler steuert, wie genau Codeabschnitte bei der Anwendung von Diffs übereinstimmen müssen. Niedrigere Werte ermöglichen eine flexiblere Übereinstimmung, erhöhen aber das Risiko falscher Ersetzungen. Verwenden Sie Werte unter 100 % mit äußerster Vorsicht."
 			}
 		}
 	},
 	"experimental": {
 		"DIFF_STRATEGY_UNIFIED": {
 			"name": "Experimentelle einheitliche Diff-Strategie verwenden",
-			"description": "Aktiviert die experimentelle einheitliche Diff-Strategie. Diese Strategie könnte die Anzahl der durch Modellfehler verursachten Wiederholungen reduzieren, kann aber unerwartetes Verhalten oder falsche Bearbeitungen verursachen. Nur aktivieren, wenn du die Risiken verstehst und bereit bist, alle Änderungen sorgfältig zu überprüfen."
+			"description": "Aktiviere die experimentelle einheitliche Diff-Strategie. Diese Strategie könnte die Anzahl der durch Modellfehler verursachten Wiederholungsversuche reduzieren, kann aber zu unerwartetem Verhalten oder falschen Bearbeitungen führen. Aktiviere sie nur, wenn du die Risiken verstehst und bereit bist, alle Änderungen sorgfältig zu überprüfen."
 		},
 		"SEARCH_AND_REPLACE": {
 			"name": "Experimentelles Such- und Ersetzungswerkzeug verwenden",
-			"description": "Aktiviert das experimentelle Such- und Ersetzungswerkzeug, das Roo ermöglicht, mehrere Instanzen eines Suchbegriffs in einer Anfrage zu ersetzen."
+			"description": "Aktiviere das experimentelle Such- und Ersetzungswerkzeug, mit dem Roo mehrere Instanzen eines Suchbegriffs in einer Anfrage ersetzen kann."
 		},
 		"INSERT_BLOCK": {
-			"name": "Experimentelles Inhalts-Einfüge-Werkzeug verwenden",
-			"description": "Aktiviert das experimentelle Inhalts-Einfüge-Werkzeug, das Roo ermöglicht, Inhalte an bestimmten Zeilennummern einzufügen, ohne einen Diff erstellen zu müssen."
+			"name": "Experimentelles Inhalts-Einfügewerkzeug verwenden",
+			"description": "Aktiviere das experimentelle Inhalts-Einfügewerkzeug, mit dem Roo Inhalte an bestimmten Zeilennummern einfügen kann, ohne einen Diff erstellen zu müssen."
 		},
 		"POWER_STEERING": {
-			"name": "Experimentellen \"Servolenkung\"-Modus verwenden",
-			"description": "Wenn aktiviert, wird Roo das Modell häufiger an die Details seiner aktuellen Modusdefinition erinnern. Dies führt zu einer stärkeren Einhaltung von Rollendefinitionen und benutzerdefinierten Anweisungen, verwendet aber mehr Tokens pro Nachricht."
-		},
-		"MULTI_SEARCH_AND_REPLACE": {
-			"name": "Experimentelles Multi-Block-Diff-Werkzeug verwenden",
-			"description": "Wenn aktiviert, verwendet Roo das Multi-Block-Diff-Werkzeug. Dies versucht, mehrere Codeblöcke in der Datei in einer Anfrage zu aktualisieren."
+			"name": "Experimentellen \"Power Steering\"-Modus verwenden",
+			"description": "Wenn aktiviert, erinnert Roo das Modell häufiger an die Details seiner aktuellen Modusdefinition. Dies führt zu einer stärkeren Einhaltung von Rollendefinitionen und benutzerdefinierten Anweisungen, verbraucht aber mehr Token pro Nachricht."
 		},
 		"CONCURRENT_FILE_READS": {
 			"name": "Gleichzeitiges Lesen von Dateien aktivieren",
-			"description": "Wenn aktiviert, kann Roo mehrere Dateien in einer einzigen Anfrage lesen. Wenn deaktiviert, muss Roo Dateien nacheinander lesen. Das Deaktivieren kann helfen, wenn du mit weniger leistungsfähigen Modellen arbeitest oder mehr Kontrolle über den Dateizugriff möchtest."
+			"description": "Wenn aktiviert, kann Roo mehrere Dateien in einer einzigen Anfrage lesen. Wenn deaktiviert, muss Roo Dateien einzeln lesen. Das Deaktivieren kann hilfreich sein, wenn mit weniger fähigen Modellen gearbeitet wird oder wenn du mehr Kontrolle über den Dateizugriff haben möchtest."
+		},
+		"MULTI_SEARCH_AND_REPLACE": {
+			"name": "Experimentelles Multi-Block-Diff-Tool verwenden",
+			"description": "Wenn aktiviert, wird Roo das Multi-Block-Diff-Tool verwenden. Dies wird versuchen, mehrere Codeblöcke in der Datei in einer Anfrage zu aktualisieren."
 		},
 		"MARKETPLACE": {
-			"name": "Marketplace aktivieren",
-			"description": "Wenn aktiviert, kannst du MCP und benutzerdefinierte Modi aus dem Marketplace installieren und verwalten."
+			"name": "Marktplatz aktivieren",
+			"description": "Wenn aktiviert, können Sie MCPs und benutzerdefinierte Modi aus dem Marketplace installieren."
 		},
 		"MULTI_FILE_APPLY_DIFF": {
 			"name": "Gleichzeitige Dateibearbeitungen aktivieren",
-			"description": "Wenn aktiviert, kann Roo mehrere Dateien in einer einzigen Anfrage bearbeiten. Wenn deaktiviert, muss Roo Dateien einzeln bearbeiten. Das Deaktivieren kann helfen, wenn du mit weniger fähigen Modellen arbeitest oder mehr Kontrolle über Dateiänderungen haben möchtest."
+			"description": "Wenn aktiviert, kann Roo mehrere Dateien in einer einzigen Anfrage bearbeiten. Wenn deaktiviert, muss Roo Dateien einzeln bearbeiten. Das Deaktivieren kann hilfreich sein, wenn mit weniger fähigen Modellen gearbeitet wird oder wenn du mehr Kontrolle über Dateiänderungen haben möchtest."
 		}
 	},
 	"promptCaching": {
@@ -575,16 +576,16 @@
 	},
 	"temperature": {
 		"useCustom": "Benutzerdefinierte Temperatur verwenden",
-		"description": "Steuert die Zufälligkeit in den Antworten des Modells.",
+		"description": "Steuert die Zufälligkeit der Modellantworten.",
 		"rangeDescription": "Höhere Werte machen die Ausgabe zufälliger, niedrigere Werte machen sie deterministischer."
 	},
 	"modelInfo": {
 		"supportsImages": "Unterstützt Bilder",
 		"noImages": "Unterstützt keine Bilder",
-		"supportsComputerUse": "Unterstützt Computer-Nutzung",
-		"noComputerUse": "Unterstützt keine Computer-Nutzung",
-		"supportsPromptCache": "Unterstützt Prompt-Caching",
-		"noPromptCache": "Unterstützt kein Prompt-Caching",
+		"supportsComputerUse": "Unterstützt Computernutzung",
+		"noComputerUse": "Unterstützt keine Computernutzung",
+		"supportsPromptCache": "Unterstützt Prompt-Cache",
+		"noPromptCache": "Unterstützt keinen Prompt-Cache",
 		"maxOutput": "Maximale Ausgabe",
 		"inputPrice": "Eingabepreis",
 		"outputPrice": "Ausgabepreis",
@@ -592,27 +593,27 @@
 		"cacheWritesPrice": "Cache-Schreibpreis",
 		"enableStreaming": "Streaming aktivieren",
 		"enableR1Format": "R1-Modellparameter aktivieren",
-		"enableR1FormatTips": "Muss aktiviert werden, wenn R1-Modelle wie QWQ verwendet werden, um 400-Fehler zu vermeiden",
+		"enableR1FormatTips": "Muss bei Verwendung von R1-Modellen wie QWQ aktiviert werden, um 400er-Fehler zu vermeiden",
 		"useAzure": "Azure verwenden",
 		"azureApiVersion": "Azure API-Version festlegen",
 		"gemini": {
 			"freeRequests": "* Kostenlos bis zu {{count}} Anfragen pro Minute. Danach hängt die Abrechnung von der Prompt-Größe ab.",
-			"pricingDetails": "Weitere Informationen finden Sie in den Preisdetails.",
+			"pricingDetails": "Weitere Informationen finden Sie unter Preisdetails.",
 			"billingEstimate": "* Die Abrechnung ist eine Schätzung - die genauen Kosten hängen von der Prompt-Größe ab."
 		}
 	},
 	"modelPicker": {
-		"automaticFetch": "Die Erweiterung ruft automatisch die neueste Liste der verfügbaren Modelle von <serviceLink>{{serviceName}}</serviceLink> ab. Wenn du dir nicht sicher bist, welches Modell du wählen sollst, funktioniert Roo Code am besten mit <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Du kannst auch nach \"free\" suchen, um derzeit verfügbare kostenlose Optionen zu finden.",
+		"automaticFetch": "Die Erweiterung ruft automatisch die neueste Liste der auf <serviceLink>{{serviceName}}</serviceLink> verfügbaren Modelle ab. Wenn du dir nicht sicher bist, welches Modell du wählen sollst, funktioniert Roo Code am besten mit <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Du kannst auch versuchen, nach \"kostenlos\" zu suchen, um die derzeit verfügbaren kostenlosen Optionen zu finden.",
 		"label": "Modell",
 		"searchPlaceholder": "Suchen",
 		"noMatchFound": "Keine Übereinstimmung gefunden",
 		"useCustomModel": "Benutzerdefiniert verwenden: {{modelId}}"
 	},
 	"footer": {
-		"feedback": "Wenn du Fragen oder Feedback hast, kannst du gerne ein Issue auf <githubLink>github.com/RooCodeInc/Roo-Code</githubLink> öffnen oder <redditLink>reddit.com/r/RooCode</redditLink> oder <discordLink>discord.gg/roocode</discordLink> beitreten",
+		"feedback": "Wenn du Fragen oder Feedback hast, kannst du gerne ein Issue auf <githubLink>github.com/RooCodeInc/Roo-Code</githubLink> eröffnen oder <redditLink>reddit.com/r/RooCode</redditLink> oder <discordLink>discord.gg/roocode</discordLink> beitreten",
 		"telemetry": {
 			"label": "Anonyme Fehler- und Nutzungsberichte zulassen",
-			"description": "Helfen Sie, Roo Code zu verbessern, indem Sie anonyme Nutzungsdaten und Fehlerberichte senden. Es werden niemals Code, Prompts oder persönliche Informationen gesendet. Weitere Details finden Sie in unserer Datenschutzrichtlinie."
+			"description": "Hilf mit, Roo Code zu verbessern, indem du anonyme Nutzungsdaten und Fehlerberichte sendest. Es werden niemals Code, Prompts oder persönliche Informationen gesendet (es sei denn, du verbindest dich mit Roo Code Cloud). Weitere Einzelheiten findest du in unserer <privacyLink>Datenschutzrichtlinie</privacyLink>."
 		},
 		"settings": {
 			"import": "Importieren",
@@ -621,19 +622,19 @@
 		}
 	},
 	"thinkingBudget": {
-		"maxTokens": "Maximale Tokens",
-		"maxThinkingTokens": "Maximale Thinking-Tokens"
+		"maxTokens": "Max Tokens",
+		"maxThinkingTokens": "Max Thinking Tokens"
 	},
 	"validation": {
 		"apiKey": "Du musst einen gültigen API-Schlüssel angeben.",
-		"awsRegion": "Du musst eine Region für Amazon Bedrock auswählen.",
+		"awsRegion": "Du musst eine Region für die Verwendung mit Amazon Bedrock auswählen.",
 		"googleCloud": "Du musst eine gültige Google Cloud Projekt-ID und Region angeben.",
 		"modelId": "Du musst eine gültige Modell-ID angeben.",
-		"modelSelector": "Du musst einen gültigen Modell-Selektor angeben.",
-		"openAi": "Du musst eine gültige Basis-URL, API-Schlüssel und Modell-ID angeben.",
+		"modelSelector": "Du musst einen gültigen Modellselektor angeben.",
+		"openAi": "Du musst eine gültige Basis-URL, einen API-Schlüssel und eine Modell-ID angeben.",
 		"arn": {
-			"invalidFormat": "Ungültiges ARN-Format. Bitte überprüfen Sie die Formatanforderungen.",
-			"regionMismatch": "Warnung: Die Region in deiner ARN ({{arnRegion}}) stimmt nicht mit deiner ausgewählten Region ({{region}}) überein. Dies kann zu Zugriffsproblemen führen. Der Provider wird die Region aus der ARN verwenden."
+			"invalidFormat": "Ungültiges ARN-Format. Bitte überprüfe die Formatanforderungen.",
+			"regionMismatch": "Warnung: Die Region in deiner ARN ({{arnRegion}}) stimmt nicht mit deiner ausgewählten Region ({{region}}) überein. Dies kann zu Zugriffsproblemen führen. Der Anbieter wird die Region aus der ARN verwenden."
 		},
 		"modelAvailability": "Die von dir angegebene Modell-ID ({{modelId}}) ist nicht verfügbar. Bitte wähle ein anderes Modell.",
 		"providerNotAllowed": "Anbieter '{{provider}}' ist von deiner Organisation nicht erlaubt",
@@ -646,7 +647,7 @@
 		"accessKey": "Zugriffsschlüssel eingeben...",
 		"secretKey": "Geheimschlüssel eingeben...",
 		"sessionToken": "Sitzungstoken eingeben...",
-		"credentialsJson": "Anmeldedaten-JSON eingeben...",
+		"credentialsJson": "Anmeldeinformationen JSON eingeben...",
 		"keyFilePath": "Schlüsseldateipfad eingeben...",
 		"projectId": "Projekt-ID eingeben...",
 		"customArn": "ARN eingeben (z.B. arn:aws:bedrock:us-east-1:123456789012:foundation-model/my-model)",
@@ -674,5 +675,5 @@
 		"useCustomArn": "Benutzerdefinierte ARN verwenden..."
 	},
 	"includeMaxOutputTokens": "Maximale Ausgabe-Tokens einbeziehen",
-	"includeMaxOutputTokensDescription": "Sende den Parameter für maximale Ausgabe-Tokens in API-Anfragen. Einige Anbieter unterstützen dies möglicherweise nicht."
+	"includeMaxOutputTokensDescription": "Senden Sie den Parameter für maximale Ausgabe-Tokens in API-Anfragen. Einige Anbieter unterstützen dies möglicherweise nicht."
 }

+ 1 - 0
webview-ui/src/i18n/locales/en/settings.json

@@ -72,6 +72,7 @@
 		"qdrantKeyLabel": "Qdrant Key:",
 		"qdrantApiKeyLabel": "Qdrant API Key",
 		"qdrantApiKeyPlaceholder": "Enter your Qdrant API key (optional)",
+		"setupConfigLabel": "Setup",
 		"advancedConfigLabel": "Advanced Configuration",
 		"searchMinScoreLabel": "Search Score Threshold",
 		"searchMinScoreDescription": "Minimum similarity score (0.0-1.0) required for search results. Lower values return more results but may be less relevant. Higher values return fewer but more relevant results.",

+ 1 - 0
webview-ui/src/i18n/locales/es/settings.json

@@ -72,6 +72,7 @@
 		"qdrantKeyLabel": "Clave de Qdrant:",
 		"qdrantApiKeyLabel": "Clave API de Qdrant",
 		"qdrantApiKeyPlaceholder": "Introduce tu clave API de Qdrant (opcional)",
+		"setupConfigLabel": "Configuración",
 		"startIndexingButton": "Iniciar",
 		"clearIndexDataButton": "Borrar índice",
 		"unsavedSettingsMessage": "Por favor guarda tus ajustes antes de iniciar el proceso de indexación.",

+ 1 - 0
webview-ui/src/i18n/locales/fr/settings.json

@@ -72,6 +72,7 @@
 		"qdrantKeyLabel": "Clé Qdrant :",
 		"qdrantApiKeyLabel": "Clé API Qdrant",
 		"qdrantApiKeyPlaceholder": "Entrez votre clé API Qdrant (optionnel)",
+		"setupConfigLabel": "Configuration",
 		"startIndexingButton": "Démarrer",
 		"clearIndexDataButton": "Effacer l'index",
 		"unsavedSettingsMessage": "Merci d'enregistrer tes paramètres avant de démarrer le processus d'indexation.",

+ 1 - 0
webview-ui/src/i18n/locales/hi/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "Ollama आधार URL",
 		"qdrantApiKeyLabel": "Qdrant API कुंजी",
 		"qdrantApiKeyPlaceholder": "अपनी Qdrant API कुंजी दर्ज करें (वैकल्पिक)",
+		"setupConfigLabel": "सेटअप",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 1 - 0
webview-ui/src/i18n/locales/id/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "URL Dasar Ollama",
 		"qdrantApiKeyLabel": "Kunci API Qdrant",
 		"qdrantApiKeyPlaceholder": "Masukkan kunci API Qdrant kamu (opsional)",
+		"setupConfigLabel": "Pengaturan",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 1 - 0
webview-ui/src/i18n/locales/it/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "URL base Ollama",
 		"qdrantApiKeyLabel": "Chiave API Qdrant",
 		"qdrantApiKeyPlaceholder": "Inserisci la tua chiave API Qdrant (opzionale)",
+		"setupConfigLabel": "Impostazione",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 1 - 0
webview-ui/src/i18n/locales/ja/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "Ollama ベースURL",
 		"qdrantApiKeyLabel": "Qdrant APIキー",
 		"qdrantApiKeyPlaceholder": "Qdrant APIキーを入力(オプション)",
+		"setupConfigLabel": "設定",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 1 - 0
webview-ui/src/i18n/locales/ko/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "Ollama 기본 URL",
 		"qdrantApiKeyLabel": "Qdrant API 키",
 		"qdrantApiKeyPlaceholder": "Qdrant API 키를 입력하세요 (선택사항)",
+		"setupConfigLabel": "설정",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 1 - 0
webview-ui/src/i18n/locales/nl/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "Ollama Basis-URL",
 		"qdrantApiKeyLabel": "Qdrant API-sleutel",
 		"qdrantApiKeyPlaceholder": "Voer je Qdrant API-sleutel in (optioneel)",
+		"setupConfigLabel": "Instellen",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 1 - 0
webview-ui/src/i18n/locales/pl/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "Bazowy URL Ollama",
 		"qdrantApiKeyLabel": "Klucz API Qdrant",
 		"qdrantApiKeyPlaceholder": "Wprowadź swój klucz API Qdrant (opcjonalnie)",
+		"setupConfigLabel": "Konfiguracja",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 1 - 0
webview-ui/src/i18n/locales/pt-BR/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "URL Base do Ollama",
 		"qdrantApiKeyLabel": "Chave da API Qdrant",
 		"qdrantApiKeyPlaceholder": "Insira sua chave da API Qdrant (opcional)",
+		"setupConfigLabel": "Configuração",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 1 - 0
webview-ui/src/i18n/locales/ru/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "Базовый URL Ollama",
 		"qdrantApiKeyLabel": "API-ключ Qdrant",
 		"qdrantApiKeyPlaceholder": "Введите ваш API-ключ Qdrant (необязательно)",
+		"setupConfigLabel": "Настройка",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 1 - 0
webview-ui/src/i18n/locales/tr/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "Ollama Temel URL",
 		"qdrantApiKeyLabel": "Qdrant API Anahtarı",
 		"qdrantApiKeyPlaceholder": "Qdrant API anahtarınızı girin (isteğe bağlı)",
+		"setupConfigLabel": "Kurulum",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 1 - 0
webview-ui/src/i18n/locales/vi/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "URL cơ sở Ollama",
 		"qdrantApiKeyLabel": "Khóa API Qdrant",
 		"qdrantApiKeyPlaceholder": "Nhập khóa API Qdrant của bạn (tùy chọn)",
+		"setupConfigLabel": "Cài đặt",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",

+ 1 - 0
webview-ui/src/i18n/locales/zh-CN/settings.json

@@ -72,6 +72,7 @@
 		"qdrantKeyLabel": "Qdrant 密钥:",
 		"qdrantApiKeyLabel": "Qdrant API 密钥",
 		"qdrantApiKeyPlaceholder": "输入你的 Qdrant API 密钥(可选)",
+		"setupConfigLabel": "设置",
 		"startIndexingButton": "开始",
 		"clearIndexDataButton": "清除索引",
 		"unsavedSettingsMessage": "请先保存设置再开始索引过程。",

+ 1 - 0
webview-ui/src/i18n/locales/zh-TW/settings.json

@@ -81,6 +81,7 @@
 		"ollamaBaseUrlLabel": "Ollama 基礎 URL",
 		"qdrantApiKeyLabel": "Qdrant API 金鑰",
 		"qdrantApiKeyPlaceholder": "輸入您的 Qdrant API 金鑰(選用)",
+		"setupConfigLabel": "設定",
 		"ollamaUrlPlaceholder": "http://localhost:11434",
 		"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
 		"modelDimensionPlaceholder": "1536",