diff --git a/locales/ca/README.md b/locales/ca/README.md index 2c7d1788f775..371bed5e63a7 100644 --- a/locales/ca/README.md +++ b/locales/ca/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/de/README.md b/locales/de/README.md index 22b4db6399a8..48a6655c5f9b 100644 --- a/locales/de/README.md +++ b/locales/de/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/es/README.md b/locales/es/README.md index 3f0135c1d83c..092f0ec9aac6 100644 --- a/locales/es/README.md +++ b/locales/es/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/fr/README.md b/locales/fr/README.md index 9596d9cbae72..5b8814248846 100644 --- a/locales/fr/README.md +++ b/locales/fr/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/hi/README.md b/locales/hi/README.md index 53939eb80213..31d1665dd50c 100644 --- a/locales/hi/README.md +++ b/locales/hi/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/id/README.md b/locales/id/README.md index 8ec72301fc2b..357ba7d7dd60 100644 --- a/locales/id/README.md +++ b/locales/id/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/it/README.md b/locales/it/README.md index e3687df010b0..04ba75d345c9 100644 --- a/locales/it/README.md +++ b/locales/it/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/ja/README.md b/locales/ja/README.md index 16e2f0d59d76..1c6a28e16df7 100644 --- a/locales/ja/README.md +++ b/locales/ja/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/ko/README.md b/locales/ko/README.md index 6ad585859bed..0ab29c6e2b8d 100644 --- a/locales/ko/README.md +++ b/locales/ko/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/nl/README.md b/locales/nl/README.md index c8b660dfb0d8..bd34c8c32424 100644 --- a/locales/nl/README.md +++ b/locales/nl/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/pl/README.md b/locales/pl/README.md index 099c4154571f..622ace3f668a 100644 --- a/locales/pl/README.md +++ b/locales/pl/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/pt-BR/README.md b/locales/pt-BR/README.md index ea27fb3a14f2..a96e37bf0dab 100644 --- a/locales/pt-BR/README.md +++ b/locales/pt-BR/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/ru/README.md b/locales/ru/README.md index 70f1f8cd903a..8e094edc3e45 100644 --- a/locales/ru/README.md +++ b/locales/ru/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/tr/README.md b/locales/tr/README.md index a540061325aa..b92edcdb4f99 100644 --- a/locales/tr/README.md +++ b/locales/tr/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/vi/README.md b/locales/vi/README.md index 3c846d9c965c..6688d44ce8ec 100644 --- a/locales/vi/README.md +++ b/locales/vi/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/zh-CN/README.md b/locales/zh-CN/README.md index 5a4f5e77c14f..eabdfca118f1 100644 --- a/locales/zh-CN/README.md +++ b/locales/zh-CN/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/locales/zh-TW/README.md b/locales/zh-TW/README.md index 240d6794c409..402a4f90fe49 100644 --- a/locales/zh-TW/README.md +++ b/locales/zh-TW/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index 579356ae2d45..e20fcecc94df 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -52,6 +52,15 @@ export const globalSettingsSchema = z.object({ currentApiConfigName: z.string().optional(), listApiConfigMeta: z.array(providerSettingsEntrySchema).optional(), pinnedApiConfigs: z.record(z.string(), z.boolean()).optional(), + apiConfigsCustomOrder: z + .array( + z.object({ + id: z.string(), + index: z.number(), + pinned: z.boolean(), + }), + ) + .optional(), lastShownAnnouncementId: z.string().optional(), customInstructions: z.string().optional(), @@ -284,6 +293,7 @@ export const EVALS_SETTINGS: RooCodeSettings = { lastShownAnnouncementId: "jul-09-2025-3-23-0", pinnedApiConfigs: {}, + apiConfigsCustomOrder: [], autoApprovalEnabled: true, alwaysAllowReadOnly: true, diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index f73a36d445ee..7ae8b0434c6f 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1881,6 +1881,7 @@ export class ClineProvider openRouterImageApiKey, openRouterImageGenerationSelectedModel, openRouterUseMiddleOutTransform, + apiConfigsCustomOrder, featureRoomoteControlEnabled, } = await this.getState() @@ -1968,6 +1969,7 @@ export class ClineProvider currentApiConfigName: currentApiConfigName ?? "default", listApiConfigMeta: listApiConfigMeta ?? [], pinnedApiConfigs: pinnedApiConfigs ?? {}, + apiConfigsCustomOrder: apiConfigsCustomOrder ?? [], mode: mode ?? defaultModeSlug, customModePrompts: customModePrompts ?? {}, customSupportPrompts: customSupportPrompts ?? {}, @@ -2194,6 +2196,7 @@ export class ClineProvider currentApiConfigName: stateValues.currentApiConfigName ?? "default", listApiConfigMeta: stateValues.listApiConfigMeta ?? [], pinnedApiConfigs: stateValues.pinnedApiConfigs ?? {}, + apiConfigsCustomOrder: stateValues.apiConfigsCustomOrder ?? [], modeApiConfigs: stateValues.modeApiConfigs ?? ({} as Record), customModePrompts: stateValues.customModePrompts ?? {}, customSupportPrompts: stateValues.customSupportPrompts ?? {}, diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index c06729674503..273c46a0f3e5 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -1699,6 +1699,22 @@ export const webviewMessageHandler = async ( await provider.postStateToWebview() } break + case "setApiConfigsCustomOrder": + if (message.values && Array.isArray(message.values.customOrder)) { + const isValidOrder = message.values.customOrder.every( + (item: any) => + typeof item === "object" && + typeof item.id === "string" && + typeof item.index === "number" && + typeof item.pinned === "boolean", + ) + + if (isValidOrder) { + await updateGlobalState("apiConfigsCustomOrder", message.values.customOrder) + await provider.postStateToWebview() + } + } + break case "enhancementApiConfigId": await updateGlobalState("enhancementApiConfigId", message.text) await provider.postStateToWebview() diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 7d2759c91905..28398e4b6cc9 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -218,6 +218,7 @@ export type ExtensionState = Pick< | "currentApiConfigName" | "listApiConfigMeta" | "pinnedApiConfigs" + | "apiConfigsCustomOrder" // | "lastShownAnnouncementId" | "customInstructions" // | "taskHistory" // Optional in GlobalSettings, required here. diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index f10808cd428d..bbc470a38256 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -181,6 +181,7 @@ export interface WebviewMessage { | "includeCurrentCost" | "searchFiles" | "toggleApiConfigPin" + | "setApiConfigsCustomOrder" | "setHistoryPreviewCollapsed" | "hasOpenedModeSelector" | "cloudButtonClicked" diff --git a/webview-ui/src/components/chat/ApiConfigSelector.tsx b/webview-ui/src/components/chat/ApiConfigSelector.tsx index 4396019a2d27..16ea2a9d4ad0 100644 --- a/webview-ui/src/components/chat/ApiConfigSelector.tsx +++ b/webview-ui/src/components/chat/ApiConfigSelector.tsx @@ -4,11 +4,88 @@ import { Fzf } from "fzf" import { cn } from "@/lib/utils" import { useRooPortal } from "@/components/ui/hooks/useRooPortal" import { Popover, PopoverContent, PopoverTrigger, StandardTooltip } from "@/components/ui" -import { useAppTranslation } from "@/i18n/TranslationContext" import { vscode } from "@/utils/vscode" import { Button } from "@/components/ui" import { IconButton } from "./IconButton" +import { useAppTranslation } from "@/i18n/TranslationContext" + +interface ConfigItemProps { + config: { id: string; name: string; modelId?: string } + isPinned: boolean + index: number + value: string + onSelect: (configId: string) => void + togglePinnedApiConfig: (id: string) => void +} + +const ConfigItem = ({ config, isPinned, index, value, onSelect, togglePinnedApiConfig }: ConfigItemProps) => { + const { t } = useAppTranslation() + const isCurrentConfig = config.id === value + + return ( +
onSelect(config.id)} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault() + onSelect(config.id) + } + }} + className={cn( + "px-3 py-1.5 text-sm flex items-center group relative", + "cursor-pointer hover:bg-vscode-list-hoverBackground", + isCurrentConfig && + "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground", + )}> +
+ {config.name} + {config.modelId && ( + <> + + {config.modelId} + + + )} +
+ +
+ {isCurrentConfig && ( +
+ +
+ )} + + + +
+
+ ) +} interface ApiConfigSelectorProps { value: string @@ -36,33 +113,28 @@ export const ApiConfigSelector = ({ const { t } = useAppTranslation() const [open, setOpen] = useState(false) const [searchValue, setSearchValue] = useState("") - const portalContainer = useRooPortal("roo-portal") - // Create searchable items for fuzzy search. - const searchableItems = useMemo( - () => - listApiConfigMeta.map((config) => ({ - original: config, - searchStr: config.name, - })), - [listApiConfigMeta], - ) + // No explicit sort mode in Chat; use custom order if available, otherwise alphabetical - // Create Fzf instance. - const fzfInstance = useMemo( - () => new Fzf(searchableItems, { selector: (item) => item.searchStr }), - [searchableItems], - ) + const portalContainer = useRooPortal("roo-portal") + + // Sort configs alphabetically (case-insensitive, natural A–Z) + const sortedConfigs = useMemo(() => { + const sorted = [...listApiConfigMeta] + sorted.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: "base", numeric: true })) + return sorted + }, [listApiConfigMeta]) // Filter configs based on search. const filteredConfigs = useMemo(() => { if (!searchValue) { - return listApiConfigMeta + return sortedConfigs } - const matchingItems = fzfInstance.find(searchValue).map((result) => result.item.original) + const fzf = new Fzf(sortedConfigs, { selector: (item) => item.name }) + const matchingItems = fzf.find(searchValue).map((result) => result.item) return matchingItems - }, [listApiConfigMeta, searchValue, fzfInstance]) + }, [sortedConfigs, searchValue]) // Separate pinned and unpinned configs. const { pinnedConfigs, unpinnedConfigs } = useMemo(() => { @@ -85,62 +157,6 @@ export const ApiConfigSelector = ({ setOpen(false) }, []) - const renderConfigItem = useCallback( - (config: { id: string; name: string; modelId?: string }, isPinned: boolean) => { - const isCurrentConfig = config.id === value - - return ( -
handleSelect(config.id)} - className={cn( - "px-3 py-1.5 text-sm cursor-pointer flex items-center group", - "hover:bg-vscode-list-hoverBackground", - isCurrentConfig && - "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground", - )}> -
- {config.name} - {config.modelId && ( - <> - - {config.modelId} - - - )} -
-
- {isCurrentConfig && ( -
- -
- )} - - - -
-
- ) - }, - [value, handleSelect, t, togglePinnedApiConfig], - ) - return ( @@ -193,11 +209,14 @@ export const ApiConfigSelector = ({ )} - {/* Config list - single scroll container */} + {/* Config list - single scroll container with a11y attributes and sticky pinned structure */} {filteredConfigs.length === 0 && searchValue ? (
{t("common:ui.no_results")}
) : ( -
+
{/* Pinned configs - sticky header */} {pinnedConfigs.length > 0 && (
0 && "border-b border-vscode-dropdown-foreground/10", )} aria-label="Pinned configurations"> - {pinnedConfigs.map((config) => renderConfigItem(config, true))} + {pinnedConfigs.map((config, index) => ( + + ))}
)} {/* Unpinned configs */} {unpinnedConfigs.length > 0 && (
- {unpinnedConfigs.map((config) => renderConfigItem(config, false))} + {unpinnedConfigs.map((config, index) => ( + + ))}
)}
)} - {/* Bottom bar with buttons on left and title on right */} -
-
- -
+ {/* Bottom bar with controls */} +
+ {/* No sort controls in Chat dropdown per design feedback */} - {/* Info icon and title on the right with matching spacing */} -
- {listApiConfigMeta.length > 6 && ( - - - - )} -

- {t("prompts:apiConfiguration.title")} -

+ {/* Bottom bar with settings and title */} +
+
+ +
+ + {/* Info icon and title on the right with matching spacing */} +
+ {listApiConfigMeta.length > 6 && ( + + + + )} +

+ {t("prompts:apiConfiguration.title")} +

+
diff --git a/webview-ui/src/components/settings/ApiConfigManager.tsx b/webview-ui/src/components/settings/ApiConfigManager.tsx index 366f7a81e749..7960a50cc2e6 100644 --- a/webview-ui/src/components/settings/ApiConfigManager.tsx +++ b/webview-ui/src/components/settings/ApiConfigManager.tsx @@ -1,20 +1,18 @@ -import { memo, useEffect, useRef, useState } from "react" -import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react" -import { AlertTriangle } from "lucide-react" +import { memo, useEffect, useRef, useState, useMemo, useCallback } from "react" import type { ProviderSettingsEntry, OrganizationAllowList } from "@roo-code/types" import { useAppTranslation } from "@/i18n/TranslationContext" -import { - type SearchableSelectOption, - Button, - Input, - Dialog, - DialogContent, - DialogTitle, - StandardTooltip, - SearchableSelect, -} from "@/components/ui" +import { Button, Input, Dialog, DialogContent, DialogTitle, StandardTooltip } from "@/components/ui" +import { vscode } from "@/utils/vscode" +import { useExtensionState } from "@/context/ExtensionStateContext" +import ConfigListItem from "./ConfigListItem" + +interface DragState { + isDragging: boolean + draggedIndex: number | null + dragOverIndex: number | null +} interface ApiConfigManagerProps { currentApiConfigName?: string @@ -36,53 +34,85 @@ const ApiConfigManager = ({ onUpsertConfig, }: ApiConfigManagerProps) => { const { t } = useAppTranslation() + const { apiConfigsCustomOrder: customOrder = [] } = useExtensionState() - const [isRenaming, setIsRenaming] = useState(false) const [isCreating, setIsCreating] = useState(false) - const [inputValue, setInputValue] = useState("") const [newProfileName, setNewProfileName] = useState("") const [error, setError] = useState(null) - const inputRef = useRef(null) + const [dragState, setDragState] = useState({ + isDragging: false, + draggedIndex: null, + dragOverIndex: null, + }) + const [focusedIndex, setFocusedIndex] = useState(null) + // Always allow reordering in Settings per design feedback + const isReorderingMode = true const newProfileInputRef = useRef(null) - // Check if a profile is valid based on the organization allow list - const isProfileValid = (profile: ProviderSettingsEntry): boolean => { - // If no organization allow list or allowAll is true, all profiles are valid - if (!organizationAllowList || organizationAllowList.allowAll) { - return true + const isOnlyProfile = listApiConfigMeta?.length === 1 + + // Sort configs based on custom order + const sortedConfigs = useMemo(() => { + if (!customOrder || customOrder.length === 0) { + return listApiConfigMeta } - // Check if the provider is allowed - const provider = profile.apiProvider - if (!provider) return true + const orderMap = new Map(customOrder.map((item) => [item.id, item.index])) - const providerConfig = organizationAllowList.providers[provider] - if (!providerConfig) { - return false - } + const sorted = [...listApiConfigMeta] + sorted.sort((a, b) => { + const aIndex = orderMap.get(a.id) ?? Number.MAX_SAFE_INTEGER + const bIndex = orderMap.get(b.id) ?? Number.MAX_SAFE_INTEGER + return (aIndex as number) - (bIndex as number) + }) - // If provider allows all models, profile is valid - return !!providerConfig.allowAll || !!(providerConfig.models && providerConfig.models.length > 0) - } + return sorted + }, [listApiConfigMeta, customOrder]) - const validateName = (name: string, isNewProfile: boolean): string | null => { - const trimmed = name.trim() - if (!trimmed) return t("settings:providers.nameEmpty") + // Check if a profile is valid based on the organization allow list + const isProfileValid = useCallback( + (profile: ProviderSettingsEntry): boolean => { + // If no organization allow list or allowAll is true, all profiles are valid + if (!organizationAllowList || organizationAllowList.allowAll) { + return true + } - const nameExists = listApiConfigMeta?.some((config) => config.name.toLowerCase() === trimmed.toLowerCase()) + // Check if the provider is allowed + const provider = profile.apiProvider + if (!provider) return true - // For new profiles, any existing name is invalid. - if (isNewProfile && nameExists) { - return t("settings:providers.nameExists") - } + const providerConfig = organizationAllowList.providers[provider] + if (!providerConfig) { + return false + } - // For rename, only block if trying to rename to a different existing profile. - if (!isNewProfile && nameExists && trimmed.toLowerCase() !== currentApiConfigName?.toLowerCase()) { - return t("settings:providers.nameExists") - } + // If provider allows all models, profile is valid + return !!providerConfig.allowAll || !!(providerConfig.models && providerConfig.models.length > 0) + }, + [organizationAllowList], + ) - return null - } + const validateName = useCallback( + (name: string, isNewProfile: boolean): string | null => { + const trimmed = name.trim() + if (!trimmed) return t("settings:providers.nameEmpty") + + const nameExists = listApiConfigMeta?.some((config) => config.name.toLowerCase() === trimmed.toLowerCase()) + + // For new profiles, any existing name is invalid. + if (isNewProfile && nameExists) { + return t("settings:providers.nameExists") + } + + // For rename, only block if trying to rename to a different existing profile. + if (!isNewProfile && nameExists && trimmed.toLowerCase() !== currentApiConfigName?.toLowerCase()) { + return t("settings:providers.nameExists") + } + + return null + }, + [listApiConfigMeta, currentApiConfigName, t], + ) const resetCreateState = () => { setIsCreating(false) @@ -90,20 +120,6 @@ const ApiConfigManager = ({ setError(null) } - const resetRenameState = () => { - setIsRenaming(false) - setInputValue("") - setError(null) - } - - // Focus input when entering rename mode. - useEffect(() => { - if (isRenaming) { - const timeoutId = setTimeout(() => inputRef.current?.focus(), 0) - return () => clearTimeout(timeoutId) - } - }, [isRenaming]) - // Focus input when opening new dialog. useEffect(() => { if (isCreating) { @@ -112,53 +128,168 @@ const ApiConfigManager = ({ } }, [isCreating]) + // Effect to manage focus when in reorder mode + useEffect(() => { + if (focusedIndex !== null) { + // Find the element at the focused index and focus it + const element = document.querySelector(`[data-config-item-index="${focusedIndex}"]`) as HTMLElement + if (element) { + element.focus() + } + } + }, [focusedIndex]) + // Reset state when current profile changes. useEffect(() => { resetCreateState() - resetRenameState() }, [currentApiConfigName]) - const handleSelectConfig = (configName: string) => { - if (!configName) return - onSelectConfig(configName) - } + const handleSelectConfig = useCallback( + (configName: string) => { + if (!configName) return + onSelectConfig(configName) + }, + [onSelectConfig], + ) - const handleAdd = () => { - resetCreateState() - setIsCreating(true) - } + const moveItem = useCallback( + (fromIndex: number, toIndex: number) => { + if (fromIndex === toIndex) return - const handleStartRename = () => { - setIsRenaming(true) - setInputValue(currentApiConfigName || "") - setError(null) - } + if (fromIndex < 0 || fromIndex >= sortedConfigs.length || toIndex < 0 || toIndex >= sortedConfigs.length) + return - const handleCancel = () => { - resetRenameState() - } + // Create a reordered array of configs + const reorderedConfigs = [...sortedConfigs] + const [movedItem] = reorderedConfigs.splice(fromIndex, 1) + reorderedConfigs.splice(toIndex, 0, movedItem) + + // Create new order array with updated indices, preserving pinned status + const newOrder = reorderedConfigs.map((config, index) => { + const existingOrderItem = customOrder.find((item) => item.id === config.id) + return { + id: config.id, + index, + pinned: existingOrderItem?.pinned ?? false, + } + }) + + vscode.postMessage({ + type: "setApiConfigsCustomOrder", + values: { customOrder: newOrder }, + }) + }, + [sortedConfigs, customOrder], + ) - const handleSave = () => { - const trimmedValue = inputValue.trim() - const error = validateName(trimmedValue, false) + const handleDragStart = useCallback((e: React.DragEvent, index: number) => { + setDragState({ + isDragging: true, + draggedIndex: index, + dragOverIndex: null, + }) + e.dataTransfer.effectAllowed = "move" + e.dataTransfer.setData("text/html", "") + }, []) + + const handleDragOver = useCallback((e: React.DragEvent, index: number) => { + e.preventDefault() + e.dataTransfer.dropEffect = "move" + + setDragState((prev) => { + // Only update if the dragOverIndex actually changed + if (prev.dragOverIndex !== index) { + return { + ...prev, + dragOverIndex: index, + } + } + return prev + }) + }, []) - if (error) { - setError(error) - return + // Use sorted configs as display configs + const displayConfigs = sortedConfigs + + const handleDragEnd = useCallback(() => { + const { draggedIndex, dragOverIndex } = dragState + + if (draggedIndex !== null && dragOverIndex !== null && draggedIndex !== dragOverIndex) { + moveItem(draggedIndex, dragOverIndex) } - if (isRenaming && currentApiConfigName) { - if (currentApiConfigName === trimmedValue) { - resetRenameState() - return + setDragState({ + isDragging: false, + draggedIndex: null, + dragOverIndex: null, + }) + }, [dragState, moveItem]) + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent, displayIndex: number) => { + const currentConfig = displayConfigs[displayIndex] + if (!currentConfig) return + + const totalItems = displayConfigs.length + + if (e.altKey || e.metaKey) { + // Alt/Option + arrow keys for reordering + if (e.key === "ArrowUp" && displayIndex > 0) { + e.preventDefault() + moveItem(displayIndex, displayIndex - 1) + } else if (e.key === "ArrowDown" && displayIndex < totalItems - 1) { + e.preventDefault() + moveItem(displayIndex, displayIndex + 1) + } + } else { + // Plain arrow keys for navigation + if (e.key === "ArrowUp" && displayIndex > 0) { + e.preventDefault() + setFocusedIndex(displayIndex - 1) + } else if (e.key === "ArrowDown" && displayIndex < totalItems - 1) { + e.preventDefault() + setFocusedIndex(displayIndex + 1) + } else if (e.key === "Enter" || e.key === " ") { + e.preventDefault() + handleSelectConfig(currentConfig.name) + } else if (e.key === "Tab") { + e.preventDefault() + // Handle tab navigation manually + if (e.shiftKey && displayIndex > 0) { + setFocusedIndex(displayIndex - 1) + } else if (!e.shiftKey && displayIndex < totalItems - 1) { + setFocusedIndex(displayIndex + 1) + } + } } - onRenameConfig(currentApiConfigName, trimmedValue) - } + }, + [displayConfigs, moveItem, handleSelectConfig], + ) - resetRenameState() + const handleAdd = () => { + resetCreateState() + setIsCreating(true) } - const handleNewProfileSave = () => { + // Removed explicit toggle; reordering is always enabled + + const handleRename = useCallback( + (oldName: string, newName: string) => { + // No need to update custom order since ID doesn't change when renaming + onRenameConfig(oldName, newName) + }, + [onRenameConfig], + ) + + const handleDelete = useCallback( + (configName: string) => { + if (!configName || !listApiConfigMeta || listApiConfigMeta.length <= 1) return + onDeleteConfig(configName) + }, + [listApiConfigMeta, onDeleteConfig], + ) + + const handleNewProfileSave = useCallback(() => { const trimmedValue = newProfileName.trim() const error = validateName(trimmedValue, true) @@ -169,134 +300,73 @@ const ApiConfigManager = ({ onUpsertConfig(trimmedValue) resetCreateState() - } - - const handleDelete = () => { - if (!currentApiConfigName || !listApiConfigMeta || listApiConfigMeta.length <= 1) return - - // Let the extension handle both deletion and selection. - onDeleteConfig(currentApiConfigName) - } - - const isOnlyProfile = listApiConfigMeta?.length === 1 + }, [newProfileName, validateName, onUpsertConfig]) return (
- - - {isRenaming ? ( -
-
- { - const target = e as { target: { value: string } } - setInputValue(target.target.value) - setError(null) - }} - placeholder={t("settings:providers.enterNewName")} - onKeyDown={({ key }) => { - if (key === "Enter" && inputValue.trim()) { - handleSave() - } else if (key === "Escape") { - handleCancel() - } - }} - className="grow" - /> - - - - - - -
- {error && ( -
- {error} -
- )} +
+ + {/* Action buttons */} +
+ + + + + +
- ) : ( - <> -
- { - 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" - /> - - - - {currentApiConfigName && ( - <> - - - - - - - - )} +
+ {/* Config list */} +
+ {displayConfigs.length === 0 ? ( +
+ {t("settings:providers.noConfigs")}
-
- {t("settings:providers.description")} -
- - )} + ) : ( + displayConfigs.map((config, index) => ( + + )) + )} +
+ + {/* Help text */} +
+ {t("settings:providers.reorderModeHelpText")} +
string | null + onDragStart: (event: React.DragEvent, index: number) => void + onDragEnd: () => void + onDragOver: (event: React.DragEvent, index: number) => void + onSelectConfig: (configName: string) => void + onKeyDown: (event: React.KeyboardEvent, displayIndex: number) => void + onRename: (oldName: string, newName: string) => void + onDelete: (configName: string) => void +} + +const ConfigListItem = memo(function ConfigListItemComponent({ + config, + index, + isCurrentConfig, + dragState, + isFocused, + isValid, + isOnlyProfile, + isReorderingMode, + validateName, + onDragStart, + onDragEnd, + onDragOver, + onSelectConfig, + onKeyDown, + onRename, + onDelete, +}: ConfigListItemProps) { + const { t } = useAppTranslation() + const [isEditing, setIsEditing] = useState(false) + const [editingValue, setEditingValue] = useState("") + const [editingError, setEditingError] = useState(null) + const editInputRef = useRef(null) + + const isDraggedOver = dragState.dragOverIndex === index + const isDragged = dragState.draggedIndex === index + + // Focus input when entering edit mode + useEffect(() => { + if (isEditing && editInputRef.current) { + const timeoutId = setTimeout(() => editInputRef.current?.focus(), 0) + return () => clearTimeout(timeoutId) + } + }, [isEditing]) + + const handleStartEdit = useCallback(() => { + setIsEditing(true) + setEditingValue(config.name) + setEditingError(null) + }, [config.name]) + + const handleCancelEdit = useCallback(() => { + setIsEditing(false) + setEditingValue("") + setEditingError(null) + }, []) + + const handleSaveEdit = useCallback(() => { + const trimmedValue = editingValue.trim() + // Pass false for isNewProfile since this is a rename operation + const error = validateName(trimmedValue, false) + + if (error) { + setEditingError(error) + return + } + + if (config.name === trimmedValue) { + handleCancelEdit() + return + } + + onRename(config.name, trimmedValue) + handleCancelEdit() + }, [editingValue, validateName, config.name, onRename, handleCancelEdit]) + + const handleInputChange = useCallback((e: unknown) => { + const target = e as { target: { value: string } } + setEditingValue(target.target.value) + setEditingError(null) + }, []) + + const handleInputKeyDown = useCallback( + ({ key }: { key: string }) => { + if (key === "Enter" && editingValue.trim()) { + handleSaveEdit() + } else if (key === "Escape") { + handleCancelEdit() + } + }, + [editingValue, handleSaveEdit, handleCancelEdit], + ) + + if (isEditing) { + return ( +
+
+
+ {isReorderingMode ? ( +
{ + e.stopPropagation() + onDragStart(e, index) + }} + onDragEnd={onDragEnd} + onClick={(e) => e.stopPropagation()}> + +
+ ) : ( +
+ {isCurrentConfig && ( + + )} +
+ )} +
+ + + + + + + + + + +
+ + {editingError && ( +
+ {editingError} +
+ )} +
+ ) + } + + return ( +
onDragOver(e, index) : undefined} + onDrop={ + isReorderingMode + ? (e) => { + e.preventDefault() + onDragEnd() + } + : undefined + } + onClick={() => onSelectConfig(config.name)} + onKeyDown={(e) => { + onKeyDown(e, index) + if (!isReorderingMode && (e.key === "Enter" || e.key === " ")) { + e.preventDefault() + e.stopPropagation() + onSelectConfig(config.name) + } + }} + tabIndex={isFocused ? 0 : -1} + className={cn( + "px-3 py-2 text-sm flex items-center group relative border rounded-md bg-vscode-sideBar-background", + !isReorderingMode && "cursor-pointer hover:bg-vscode-list-hoverBackground", + isReorderingMode && "cursor-move", + isCurrentConfig && + "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground border-vscode-focusBorder", + !isCurrentConfig && "border-vscode-dropdown-border", + isDragged && "opacity-50", + isDraggedOver && "border-t-2 border-vscode-focusBorder", + isFocused && "ring-1 ring-vscode-focusBorder", + !isValid && "opacity-60", + )} + draggable={isReorderingMode} + onDragStart={ + isReorderingMode + ? (e) => { + e.stopPropagation() + onDragStart(e, index) + } + : undefined + } + onDragEnd={isReorderingMode ? onDragEnd : undefined}> +
+ {isReorderingMode ? ( +
+ +
+ ) : ( +
+ {isCurrentConfig && } +
+ )} +
+ +
+ {!isValid && ( + + + + )} + {config.name} + {config.modelId && ( + + {config.modelId} + + )} +
+ +
+ + + + + + + +
+
+ ) +}) + +export default ConfigListItem diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index 506eabc4cb50..25764a089bbf 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -317,6 +317,33 @@ const SettingsView = forwardRef(({ onDone, t }) }, []) + const handleDeleteConfig = useCallback((configName: string) => { + vscode.postMessage({ type: "deleteApiConfiguration", text: configName }) + }, []) + + const handleRenameConfig = useCallback( + (oldName: string, newName: string) => { + vscode.postMessage({ + type: "renameApiConfiguration", + values: { oldName, newName }, + apiConfiguration, + }) + prevApiConfigName.current = newName + }, + [apiConfiguration], + ) + + const handleUpsertConfig = useCallback( + (configName: string) => { + vscode.postMessage({ + type: "upsertApiConfiguration", + text: configName, + apiConfiguration, + }) + }, + [apiConfiguration], + ) + const isSettingValid = !errorMessage const handleSubmit = () => { @@ -414,6 +441,13 @@ const SettingsView = forwardRef(({ onDone, t [isChangeDetected], ) + const handleSelectConfig = useCallback( + (configName: string) => { + checkUnsaveChanges(() => vscode.postMessage({ type: "loadApiConfiguration", text: configName })) + }, + [checkUnsaveChanges], + ) + useImperativeHandle(ref, () => ({ checkUnsaveChanges }), [checkUnsaveChanges]) const onConfirmDialogResult = useCallback( @@ -638,29 +672,10 @@ const SettingsView = forwardRef(({ onDone, t - checkUnsaveChanges(() => - vscode.postMessage({ type: "loadApiConfiguration", text: configName }), - ) - } - onDeleteConfig={(configName: string) => - vscode.postMessage({ type: "deleteApiConfiguration", text: configName }) - } - onRenameConfig={(oldName: string, newName: string) => { - vscode.postMessage({ - type: "renameApiConfiguration", - values: { oldName, newName }, - apiConfiguration, - }) - prevApiConfigName.current = newName - }} - onUpsertConfig={(configName: string) => - vscode.postMessage({ - type: "upsertApiConfiguration", - text: configName, - apiConfiguration, - }) - } + onSelectConfig={handleSelectConfig} + onDeleteConfig={handleDeleteConfig} + onRenameConfig={handleRenameConfig} + onUpsertConfig={handleUpsertConfig} /> ({ + useExtensionState: () => ({ + apiConfigsCustomOrder: [ + { id: "config1", index: 0 }, + { id: "config2", index: 1 }, + { id: "config3", index: 2 }, + ], + }), +})) + +// Mock the translation hook +vitest.mock("@/i18n/TranslationContext", () => ({ + useAppTranslation: () => ({ + t: (key: string) => key, + }), +})) + // Mock VSCode components vitest.mock("@vscode/webview-ui-toolkit/react", () => ({ VSCodeTextField: ({ value, onInput, placeholder, onKeyDown, "data-testid": dataTestId }: any) => ( @@ -27,8 +45,8 @@ vitest.mock("@/components/ui", () => ({ ), DialogContent: ({ children }: any) =>
{children}
, DialogTitle: ({ children }: any) =>
{children}
, - Button: ({ children, onClick, disabled, "data-testid": dataTestId }: any) => ( - ), @@ -258,11 +276,14 @@ describe("ApiConfigManager", () => { it("allows selecting a different config", () => { render() - // The SearchableSelect mock renders as a simple select element - const selectElement = screen.getByTestId("select-component") as HTMLSelectElement + // Find the config item for "Another Config" and click it + const configItems = screen.getAllByRole("option") + const anotherConfigItem = configItems.find((item) => + item.getAttribute("aria-label")?.includes("Another Config"), + ) - // Change the select value to "Another Config" - fireEvent.change(selectElement, { target: { value: "Another Config" } }) + expect(anotherConfigItem).toBeDefined() + fireEvent.click(anotherConfigItem!) expect(mockOnSelectConfig).toHaveBeenCalledWith("Another Config") }) @@ -343,4 +364,36 @@ describe("ApiConfigManager", () => { fireEvent.keyDown(input, { key: "Escape" }) expect(screen.queryByDisplayValue("New Name")).not.toBeInTheDocument() }) + + describe("Reordering Mode", () => { + const mockConfigsForReordering = [ + { id: "1", name: "config1", apiProvider: "openai" as const, modelId: "gpt-4" }, + { id: "2", name: "config2", apiProvider: "anthropic" as const, modelId: "claude-3" }, + { id: "3", name: "config3", apiProvider: "openai" as const, modelId: "gpt-3.5" }, + ] + + const reorderingProps = { + ...defaultProps, + currentApiConfigName: "config1", + listApiConfigMeta: mockConfigsForReordering, + } + + it("shows reset-to-alphabetical button", () => { + render() + const resetBtn = screen.getByTestId("reset-to-alphabetical-button") + expect(resetBtn).toBeInTheDocument() + }) + + it("always shows reorder help text in settings", () => { + render() + expect(screen.getByText("settings:providers.reorderModeHelpText")).toBeInTheDocument() + }) + + it("allows click selection while reordering", () => { + render() + const configItems = screen.getAllByRole("option") + fireEvent.click(configItems[1]) + expect(mockOnSelectConfig).toHaveBeenCalled() + }) + }) }) diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index 6443ccad93d5..37363c67b864 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -243,6 +243,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode maxImageFileSize: 5, // Default max image file size in MB maxTotalImageSize: 20, // Default max total image size in MB pinnedApiConfigs: {}, // Empty object for pinned API configs + apiConfigsCustomOrder: [], // Empty array for API config custom order terminalZshOhMy: false, // Default Oh My Zsh integration setting maxConcurrentFileReads: 5, // Default concurrent file reads terminalZshP10k: false, // Default Powerlevel10k integration setting diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 16ea62c44390..b58adbdd3140 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Obrir tasca a Roo Code Cloud", "openInCloudIntro": "Continua monitoritzant o interactuant amb Roo des de qualsevol lloc. Escaneja, fes clic o copia per obrir." }, - "unpin": "Desfixar", - "pin": "Fixar", "tokenProgress": { "availableSpace": "Espai disponible: {{amount}} tokens", "tokensUsed": "Tokens utilitzats: {{used}} de {{total}}", @@ -421,13 +419,21 @@ "clickToEdit": "Feu clic per editar el missatge" }, "slashCommand": { - "wantsToRun": "Roo vol executar una comanda slash", - "didRun": "Roo ha executat una comanda slash" + "wantsToRun": "Roo vol executar una comanda slash:", + "didRun": "Roo ha executat una comanda slash:" }, "contextMenu": { "noResults": "Sense resultats", "problems": "Problemes", "terminal": "Terminal", "url": "Enganxa la URL per obtenir-ne el contingut" + }, + "apiConfigSelector": { + "unpin": "Desfixar", + "pin": "Fixar", + "sort": "Ordenar", + "alphabetical": "A–Z", + "custom": "Personalitzat", + "editConfigurations": "Editar configuracions" } } diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 20f693cfcae4..3fe4ecc3a7b4 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "Introduïu el nom del perfil", "createProfile": "Crea perfil", "cannotDeleteOnlyProfile": "No es pot eliminar l'únic perfil", + "exitReorderMode": "Sortir del mode de reordenació", + "reorderProfiles": "Reordenar perfils", + "noConfigs": "No s'han trobat perfils de configuració", + "reorderModeHelpText": "Utilitzeu Alt/Option + tecles de fletxa per reordenar perfils, o arrossegueu-los i deixeu-los anar", + "normalModeHelpText": "Feu clic en un perfil per seleccionar-lo, o utilitzeu els botons d'acció per gestionar perfils", "searchPlaceholder": "Cerca perfils", "searchProviderPlaceholder": "Cerca proveïdors", "noProviderMatchFound": "No s'han trobat proveïdors", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index a3f14d12549b..3a6f862a65f7 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Aufgabe in Roo Code Cloud öffnen", "openInCloudIntro": "Überwache oder interagiere mit Roo von überall aus. Scanne, klicke oder kopiere zum Öffnen." }, - "unpin": "Lösen von oben", - "pin": "Anheften", "tokenProgress": { "availableSpace": "Verfügbarer Speicher: {{amount}} Tokens", "tokensUsed": "Verwendete Tokens: {{used}} von {{total}}", @@ -427,7 +425,21 @@ "clickToEdit": "Klicken zum Bearbeiten der Nachricht" }, "slashCommand": { - "wantsToRun": "Roo möchte einen Slash-Befehl ausführen", - "didRun": "Roo hat einen Slash-Befehl ausgeführt" + "wantsToRun": "Roo möchte einen Slash-Befehl ausführen:", + "didRun": "Roo hat einen Slash-Befehl ausgeführt:" + }, + "contextMenu": { + "noResults": "Keine Ergebnisse", + "problems": "Probleme", + "terminal": "Terminal", + "url": "URL einfügen, um Inhalte abzurufen" + }, + "apiConfigSelector": { + "unpin": "Lösen", + "pin": "Anheften", + "sort": "Sortieren", + "alphabetical": "A–Z", + "custom": "Benutzerdefiniert", + "editConfigurations": "Konfigurationen bearbeiten" } } diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 3b7902812e35..15572f2ff125 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "Profilnamen eingeben", "createProfile": "Profil erstellen", "cannotDeleteOnlyProfile": "Das einzige Profil kann nicht gelöscht werden", + "exitReorderMode": "Neuordnungsmodus verlassen", + "reorderProfiles": "Profile neu ordnen", + "noConfigs": "Keine Konfigurationsprofile gefunden", + "reorderModeHelpText": "Verwenden Sie Alt/Option + Pfeiltasten, um Profile neu zu ordnen, oder ziehen und lassen Sie sie fallen", + "normalModeHelpText": "Klicken Sie auf ein Profil, um es auszuwählen, oder verwenden Sie die Aktionsschaltflächen zur Profilverwaltung", "searchPlaceholder": "Profile durchsuchen", "searchProviderPlaceholder": "Suchanbieter durchsuchen", "noProviderMatchFound": "Keine Anbieter gefunden", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index 6f47f040c67b..072d27738eeb 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Open task in Roo Code Cloud", "openInCloudIntro": "Keep monitoring or interacting with Roo from anywhere. Scan, click or copy to open." }, - "unpin": "Unpin", - "pin": "Pin", "retry": { "title": "Retry", "tooltip": "Try the operation again" @@ -421,5 +419,13 @@ "problems": "Problems", "terminal": "Terminal", "url": "Paste URL to fetch contents" + }, + "apiConfigSelector": { + "unpin": "Unpin", + "pin": "Pin", + "sort": "Sort", + "alphabetical": "A–Z", + "custom": "Custom", + "editConfigurations": "Edit configurations" } } diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 950d4d2319f5..7071461c9375 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -243,6 +243,11 @@ "enterProfileName": "Enter profile name", "createProfile": "Create Profile", "cannotDeleteOnlyProfile": "Cannot delete the only profile", + "exitReorderMode": "Exit reorder mode", + "reorderProfiles": "Reorder profiles", + "noConfigs": "No configuration profiles found", + "reorderModeHelpText": "Use Alt/Option + arrow keys to reorder profiles, or drag and drop them", + "normalModeHelpText": "Click on a profile to select it, or use the action buttons to manage profiles", "searchPlaceholder": "Search profiles", "searchProviderPlaceholder": "Search providers", "noProviderMatchFound": "No providers found", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index e6084b371399..e335a766850f 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Abrir tarea en Roo Code Cloud", "openInCloudIntro": "Continúa monitoreando o interactuando con Roo desde cualquier lugar. Escanea, haz clic o copia para abrir." }, - "unpin": "Desfijar", - "pin": "Fijar", "retry": { "title": "Reintentar", "tooltip": "Intenta la operación de nuevo" @@ -427,7 +425,21 @@ "clickToEdit": "Haz clic para editar el mensaje" }, "slashCommand": { - "wantsToRun": "Roo quiere ejecutar un comando slash", - "didRun": "Roo ejecutó un comando slash" + "wantsToRun": "Roo quiere ejecutar un comando slash:", + "didRun": "Roo ejecutó un comando slash:" + }, + "contextMenu": { + "noResults": "No hay resultados", + "problems": "Problemas", + "terminal": "Terminal", + "url": "Pega la URL para obtener el contenido" + }, + "apiConfigSelector": { + "unpin": "Desfijar", + "pin": "Fijar", + "sort": "Ordenar", + "alphabetical": "A–Z", + "custom": "Personalizado", + "editConfigurations": "Editar configuraciones" } } diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 24ba907958a3..0cf39c785d92 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "Ingrese el nombre del perfil", "createProfile": "Crear perfil", "cannotDeleteOnlyProfile": "No se puede eliminar el único perfil", + "exitReorderMode": "Salir del modo de reordenación", + "reorderProfiles": "Reordenar perfiles", + "noConfigs": "No se encontraron perfiles de configuración", + "reorderModeHelpText": "Usa Alt/Opción + teclas de flecha para reordenar perfiles, o arrástralos y suéltalos", + "normalModeHelpText": "Haz clic en un perfil para seleccionarlo, o usa los botones de acción para gestionar perfiles", "searchPlaceholder": "Buscar perfiles", "searchProviderPlaceholder": "Buscar proveedores", "noProviderMatchFound": "No se encontraron proveedores", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index 38d63358ca98..a92623f02ba6 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Ouvrir la tâche dans Roo Code Cloud", "openInCloudIntro": "Continue à surveiller ou interagir avec Roo depuis n'importe où. Scanne, clique ou copie pour ouvrir." }, - "unpin": "Désépingler", - "pin": "Épingler", "tokenProgress": { "availableSpace": "Espace disponible : {{amount}} tokens", "tokensUsed": "Tokens utilisés : {{used}} sur {{total}}", @@ -427,7 +425,21 @@ "clickToEdit": "Cliquez pour modifier le message" }, "slashCommand": { - "wantsToRun": "Roo veut exécuter une commande slash", - "didRun": "Roo a exécuté une commande slash" + "wantsToRun": "Roo veut exécuter une commande slash:", + "didRun": "Roo a exécuté une commande slash:" + }, + "contextMenu": { + "noResults": "Aucun résultat", + "problems": "Problèmes", + "terminal": "Terminal", + "url": "Coller l'URL pour récupérer le contenu" + }, + "apiConfigSelector": { + "unpin": "Désépingler", + "pin": "Épingler", + "sort": "Trier", + "alphabetical": "A–Z", + "custom": "Personnalisé", + "editConfigurations": "Modifier les configurations" } } diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index fbcc6914d692..a6fb89fddd3f 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "Entrez le nom du profil", "createProfile": "Créer un profil", "cannotDeleteOnlyProfile": "Impossible de supprimer le seul profil", + "exitReorderMode": "Quitter le mode de réorganisation", + "reorderProfiles": "Réorganiser les profils", + "noConfigs": "Aucun profil de configuration trouvé", + "reorderModeHelpText": "Utilisez Alt/Option + touches fléchées pour réorganiser les profils, ou glissez-déposez-les", + "normalModeHelpText": "Cliquez sur un profil pour le sélectionner, ou utilisez les boutons d'action pour gérer les profils", "searchPlaceholder": "Rechercher des profils", "searchProviderPlaceholder": "Rechercher des fournisseurs", "noProviderMatchFound": "Aucun fournisseur trouvé", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 9bc4b4619766..48a6a9e2194d 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Roo Code Cloud में कार्य खोलें", "openInCloudIntro": "कहीं से भी Roo की निगरानी या इंटरैक्ट करना जारी रखें। खोलने के लिए स्कैन करें, क्लिक करें या कॉपी करें।" }, - "unpin": "पिन करें", - "pin": "अवपिन करें", "tokenProgress": { "availableSpace": "उपलब्ध स्थान: {{amount}} tokens", "tokensUsed": "प्रयुक्त tokens: {{used}} / {{total}}", @@ -427,7 +425,21 @@ "clickToEdit": "संदेश संपादित करने के लिए क्लिक करें" }, "slashCommand": { - "wantsToRun": "Roo एक स्लैश कमांड चलाना चाहता है", - "didRun": "Roo ने एक स्लैश कमांड चलाया" + "wantsToRun": "Roo एक स्लैश कमांड चलाना चाहता है:", + "didRun": "Roo ने एक स्लैश कमांड चलाया:" + }, + "contextMenu": { + "noResults": "कोई परिणाम नहीं", + "problems": "समस्याएँ", + "terminal": "टर्मिनल", + "url": "सामग्री लाने के लिए URL पेस्ट करें" + }, + "apiConfigSelector": { + "unpin": "अनपिन करें", + "pin": "पिन करें", + "sort": "क्रमबद्ध करें", + "alphabetical": "A–Z", + "custom": "कस्टम", + "editConfigurations": "कॉन्फ़िगरेशन संपादित करें" } } diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index a362fd301cdf..d79ee24b54c7 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "प्रोफ़ाइल नाम दर्ज करें", "createProfile": "प्रोफ़ाइल बनाएं", "cannotDeleteOnlyProfile": "केवल एकमात्र प्रोफ़ाइल को हटाया नहीं जा सकता", + "exitReorderMode": "पुनः क्रम मोड से बाहर निकलें", + "reorderProfiles": "प्रोफ़ाइल को पुनः क्रमित करें", + "noConfigs": "कोई कॉन्फ़िगरेशन प्रोफ़ाइल नहीं मिला", + "reorderModeHelpText": "प्रोफ़ाइल को पुनः क्रमित करने के लिए Alt/Option + तीर कुंजियों का उपयोग करें, या उन्हें खींचें और छोड़ें", + "normalModeHelpText": "प्रोफ़ाइल चुनने के लिए उस पर क्लिक करें, या प्रोफ़ाइल प्रबंधित करने के लिए एक्शन बटन का उपयोग करें", "searchPlaceholder": "प्रोफ़ाइल खोजें", "searchProviderPlaceholder": "प्रदाता खोजें", "noProviderMatchFound": "कोई प्रदाता नहीं मिला", diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index b61b47b3d884..48fcce429a8d 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -31,8 +31,6 @@ "history": { "title": "Riwayat" }, - "unpin": "Lepas Pin", - "pin": "Pin", "retry": { "title": "Coba Lagi", "tooltip": "Coba operasi lagi" @@ -433,7 +431,21 @@ "clickToEdit": "Klik untuk mengedit pesan" }, "slashCommand": { - "wantsToRun": "Roo ingin menjalankan perintah slash", - "didRun": "Roo telah menjalankan perintah slash" + "wantsToRun": "Roo ingin menjalankan perintah slash:", + "didRun": "Roo telah menjalankan perintah slash:" + }, + "contextMenu": { + "noResults": "Tidak ada hasil", + "problems": "Masalah", + "terminal": "Terminal", + "url": "Tempel URL untuk mengambil konten" + }, + "apiConfigSelector": { + "unpin": "Lepas Pin", + "pin": "Sematkan", + "sort": "Urutkan", + "alphabetical": "A–Z", + "custom": "Kustom", + "editConfigurations": "Edit konfigurasi" } } diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index aad93a749b09..255e4f41196f 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -242,6 +242,11 @@ "enterProfileName": "Masukkan nama profil", "createProfile": "Buat Profil", "cannotDeleteOnlyProfile": "Tidak dapat menghapus satu-satunya profil", + "exitReorderMode": "Keluar dari mode pengurutan ulang", + "reorderProfiles": "Urutkan ulang profil", + "noConfigs": "Tidak ada profil konfigurasi ditemukan", + "reorderModeHelpText": "Gunakan Alt/Option + tombol panah untuk mengurutkan ulang profil, atau seret dan lepas", + "normalModeHelpText": "Klik pada profil untuk memilihnya, atau gunakan tombol aksi untuk mengelola profil", "searchPlaceholder": "Cari profil", "searchProviderPlaceholder": "Cari penyedia", "noProviderMatchFound": "Tidak ada penyedia ditemukan", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index 082c489e9313..ba6ed3e1e295 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Apri attività in Roo Code Cloud", "openInCloudIntro": "Continua a monitorare o interagire con Roo da qualsiasi luogo. Scansiona, clicca o copia per aprire." }, - "unpin": "Rilascia", - "pin": "Fissa", "tokenProgress": { "availableSpace": "Spazio disponibile: {{amount}} tokens", "tokensUsed": "Tokens utilizzati: {{used}} di {{total}}", @@ -427,7 +425,21 @@ "clickToEdit": "Clicca per modificare il messaggio" }, "slashCommand": { - "wantsToRun": "Roo vuole eseguire un comando slash", - "didRun": "Roo ha eseguito un comando slash" + "wantsToRun": "Roo vuole eseguire un comando slash:", + "didRun": "Roo ha eseguito un comando slash:" + }, + "contextMenu": { + "noResults": "Nessun risultato", + "problems": "Problemi", + "terminal": "Terminale", + "url": "Incolla l'URL per recuperare i contenuti" + }, + "apiConfigSelector": { + "unpin": "Sblocca", + "pin": "Blocca", + "sort": "Ordina", + "alphabetical": "A–Z", + "custom": "Personalizzato", + "editConfigurations": "Modifica configurazioni" } } diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 63ed2b2f0462..c1d8b77a836f 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "Inserisci il nome del profilo", "createProfile": "Crea profilo", "cannotDeleteOnlyProfile": "Impossibile eliminare l'unico profilo", + "exitReorderMode": "Esci dalla modalità di riordino", + "reorderProfiles": "Riordina profili", + "noConfigs": "Nessun profilo di configurazione trovato", + "reorderModeHelpText": "Usa Alt/Option + tasti freccia per riordinare i profili, o trascinali e rilasciali", + "normalModeHelpText": "Clicca su un profilo per selezionarlo, o usa i pulsanti di azione per gestire i profili", "searchPlaceholder": "Cerca profili", "noMatchFound": "Nessun profilo corrispondente trovato", "searchProviderPlaceholder": "Cerca fornitori", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 531afc067e4d..00a4e49bd3b4 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Roo Code Cloudでタスクを開く", "openInCloudIntro": "どこからでもRooの監視や操作を続けられます。スキャン、クリック、またはコピーして開いてください。" }, - "unpin": "ピン留めを解除", - "pin": "ピン留め", "tokenProgress": { "availableSpace": "利用可能な空き容量: {{amount}} トークン", "tokensUsed": "使用トークン: {{used}} / {{total}}", @@ -427,7 +425,21 @@ "clickToEdit": "クリックしてメッセージを編集" }, "slashCommand": { - "wantsToRun": "Rooはスラッシュコマンドを実行したい", - "didRun": "Rooはスラッシュコマンドを実行しました" + "wantsToRun": "Rooはスラッシュコマンドを実行したい:", + "didRun": "Rooはスラッシュコマンドを実行しました:" + }, + "contextMenu": { + "noResults": "結果なし", + "problems": "問題", + "terminal": "ターミナル", + "url": "URLを貼り付けてコンテンツを取得" + }, + "apiConfigSelector": { + "unpin": "ピン留めを解除", + "pin": "ピン留め", + "sort": "並べ替え", + "alphabetical": "A–Z", + "custom": "カスタム", + "editConfigurations": "構成を編集" } } diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 84bf98c1e441..02f2080151f9 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "プロファイル名を入力", "createProfile": "プロファイルを作成", "cannotDeleteOnlyProfile": "唯一のプロファイルは削除できません", + "exitReorderMode": "並び替えモードを終了", + "reorderProfiles": "プロファイルを並び替え", + "noConfigs": "設定プロファイルが見つかりません", + "reorderModeHelpText": "Alt/Option + 矢印キーでプロファイルを並び替えるか、ドラッグ&ドロップしてください", + "normalModeHelpText": "プロファイルをクリックして選択するか、アクションボタンを使用してプロファイルを管理してください", "searchPlaceholder": "プロファイルを検索", "searchProviderPlaceholder": "プロバイダーを検索", "noProviderMatchFound": "プロバイダーが見つかりません", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index 9f7818bc4757..a7fba16510fc 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Roo Code Cloud에서 작업 열기", "openInCloudIntro": "어디서나 Roo를 계속 모니터링하거나 상호작용할 수 있습니다. 스캔, 클릭 또는 복사하여 열기." }, - "unpin": "고정 해제하기", - "pin": "고정하기", "tokenProgress": { "availableSpace": "사용 가능한 공간: {{amount}} 토큰", "tokensUsed": "사용된 토큰: {{used}} / {{total}}", @@ -427,7 +425,21 @@ "clickToEdit": "클릭하여 메시지 편집" }, "slashCommand": { - "wantsToRun": "Roo가 슬래시 명령어를 실행하려고 합니다", - "didRun": "Roo가 슬래시 명령어를 실행했습니다" + "wantsToRun": "Roo가 슬래시 명령어를 실행하려고 합니다:", + "didRun": "Roo가 슬래시 명령어를 실행했습니다:" + }, + "contextMenu": { + "noResults": "결과 없음", + "problems": "문제", + "terminal": "터미널", + "url": "콘텐츠를 가져올 URL 붙여넣기" + }, + "apiConfigSelector": { + "unpin": "고정 해제", + "pin": "고정", + "sort": "정렬", + "alphabetical": "A–Z", + "custom": "사용자 정의", + "editConfigurations": "구성 편집" } } diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 3d7caa0ab101..8b83bebc9198 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "프로필 이름 입력", "createProfile": "프로필 생성", "cannotDeleteOnlyProfile": "유일한 프로필은 삭제할 수 없습니다", + "exitReorderMode": "재정렬 모드 종료", + "reorderProfiles": "프로필 재정렬", + "noConfigs": "구성 프로필을 찾을 수 없습니다", + "reorderModeHelpText": "Alt/Option + 화살표 키를 사용하여 프로필을 재정렬하거나 드래그 앤 드롭하세요", + "normalModeHelpText": "프로필을 클릭하여 선택하거나 액션 버튼을 사용하여 프로필을 관리하세요", "searchPlaceholder": "프로필 검색", "searchProviderPlaceholder": "공급자 검색", "noProviderMatchFound": "공급자를 찾을 수 없습니다", diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index 97380d370af0..a06089ce546a 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Taak openen in Roo Code Cloud", "openInCloudIntro": "Blijf Roo vanaf elke locatie monitoren of ermee interacteren. Scan, klik of kopieer om te openen." }, - "unpin": "Losmaken", - "pin": "Vastmaken", "retry": { "title": "Opnieuw proberen", "tooltip": "Probeer de bewerking opnieuw" @@ -427,7 +425,21 @@ "clickToEdit": "Klik om bericht te bewerken" }, "slashCommand": { - "wantsToRun": "Roo wil een slash commando uitvoeren", - "didRun": "Roo heeft een slash commando uitgevoerd" + "wantsToRun": "Roo wil een slash commando uitvoeren:", + "didRun": "Roo heeft een slash commando uitgevoerd:" + }, + "contextMenu": { + "noResults": "Geen resultaten", + "problems": "Problemen", + "terminal": "Terminal", + "url": "Plak URL om inhoud op te halen" + }, + "apiConfigSelector": { + "unpin": "Losmaken", + "pin": "Vastmaken", + "sort": "Sorteren", + "alphabetical": "A–Z", + "custom": "Aangepast", + "editConfigurations": "Configuraties bewerken" } } diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 7ce4baefb924..385c5b3edbca 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "Voer profielnaam in", "createProfile": "Profiel aanmaken", "cannotDeleteOnlyProfile": "Kan het enige profiel niet verwijderen", + "exitReorderMode": "Herordenmodus verlaten", + "reorderProfiles": "Profielen herordenen", + "noConfigs": "Geen configuratieprofielen gevonden", + "reorderModeHelpText": "Gebruik Alt/Option + pijltoetsen om profielen te herordenen, of sleep en laat ze vallen", + "normalModeHelpText": "Klik op een profiel om het te selecteren, of gebruik de actieknoppen om profielen te beheren", "searchPlaceholder": "Zoek profielen", "searchProviderPlaceholder": "Zoek providers", "noProviderMatchFound": "Geen providers gevonden", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index 414262eaa7cf..1142d03d643d 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Otwórz zadanie w Roo Code Cloud", "openInCloudIntro": "Kontynuuj monitorowanie lub interakcję z Roo z dowolnego miejsca. Zeskanuj, kliknij lub skopiuj, aby otworzyć." }, - "unpin": "Odepnij", - "pin": "Przypnij", "tokenProgress": { "availableSpace": "Dostępne miejsce: {{amount}} tokenów", "tokensUsed": "Wykorzystane tokeny: {{used}} z {{total}}", @@ -427,7 +425,21 @@ "clickToEdit": "Kliknij, aby edytować wiadomość" }, "slashCommand": { - "wantsToRun": "Roo chce uruchomić komendę slash", - "didRun": "Roo uruchomił komendę slash" + "wantsToRun": "Roo chce uruchomić komendę slash:", + "didRun": "Roo uruchomił komendę slash:" + }, + "contextMenu": { + "noResults": "Brak wyników", + "problems": "Problemy", + "terminal": "Terminal", + "url": "Wklej adres URL, aby pobrać zawartość" + }, + "apiConfigSelector": { + "unpin": "Odepnij", + "pin": "Przypnij", + "sort": "Sortuj", + "alphabetical": "A–Z", + "custom": "Niestandardowe", + "editConfigurations": "Edytuj konfiguracje" } } diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index e1853ee53e43..22345f0446c2 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "Wprowadź nazwę profilu", "createProfile": "Utwórz profil", "cannotDeleteOnlyProfile": "Nie można usunąć jedynego profilu", + "exitReorderMode": "Wyjdź z trybu zmiany kolejności", + "reorderProfiles": "Zmień kolejność profili", + "noConfigs": "Nie znaleziono profili konfiguracji", + "reorderModeHelpText": "Użyj Alt/Option + klawiszy strzałek, aby zmienić kolejność profili, lub przeciągnij i upuść je", + "normalModeHelpText": "Kliknij na profil, aby go wybrać, lub użyj przycisków akcji do zarządzania profilami", "searchPlaceholder": "Szukaj profili", "searchProviderPlaceholder": "Szukaj dostawców", "noProviderMatchFound": "Nie znaleziono dostawców", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index 0baa415bc7d3..8e5ada8ad386 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Abrir tarefa no Roo Code Cloud", "openInCloudIntro": "Continue monitorando ou interagindo com Roo de qualquer lugar. Escaneie, clique ou copie para abrir." }, - "unpin": "Desfixar", - "pin": "Fixar", "tokenProgress": { "availableSpace": "Espaço disponível: {{amount}} tokens", "tokensUsed": "Tokens usados: {{used}} de {{total}}", @@ -427,7 +425,21 @@ "clickToEdit": "Clique para editar a mensagem" }, "slashCommand": { - "wantsToRun": "Roo quer executar um comando slash", - "didRun": "Roo executou um comando slash" + "wantsToRun": "Roo quer executar um comando slash:", + "didRun": "Roo executou um comando slash:" + }, + "contextMenu": { + "noResults": "Nenhum resultado", + "problems": "Problemas", + "terminal": "Terminal", + "url": "Cole o URL para buscar o conteúdo" + }, + "apiConfigSelector": { + "unpin": "Desafixar", + "pin": "Fixar", + "sort": "Ordenar", + "alphabetical": "A–Z", + "custom": "Personalizado", + "editConfigurations": "Editar configurações" } } diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 8542cdd06649..015115452432 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "Digite o nome do perfil", "createProfile": "Criar perfil", "cannotDeleteOnlyProfile": "Não é possível excluir o único perfil", + "exitReorderMode": "Sair do modo de reordenação", + "reorderProfiles": "Reordenar perfis", + "noConfigs": "Nenhum perfil de configuração encontrado", + "reorderModeHelpText": "Use Alt/Option + teclas de seta para reordenar perfis, ou arraste e solte-os", + "normalModeHelpText": "Clique em um perfil para selecioná-lo, ou use os botões de ação para gerenciar perfis", "searchPlaceholder": "Pesquisar perfis", "searchProviderPlaceholder": "Pesquisar provedores", "noProviderMatchFound": "Nenhum provedor encontrado", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index 10cca124d355..a4b9bddf08ae 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Открыть задачу в Roo Code Cloud", "openInCloudIntro": "Продолжай отслеживать или взаимодействовать с Roo откуда угодно. Отсканируй, нажми или скопируй для открытия." }, - "unpin": "Открепить", - "pin": "Закрепить", "retry": { "title": "Повторить", "tooltip": "Попробовать выполнить операцию снова" @@ -428,7 +426,21 @@ "clickToEdit": "Нажмите, чтобы редактировать сообщение" }, "slashCommand": { - "wantsToRun": "Roo хочет выполнить слеш-команду", - "didRun": "Roo выполнил слеш-команду" + "wantsToRun": "Roo хочет выполнить слеш-команду:", + "didRun": "Roo выполнил слеш-команду:" + }, + "contextMenu": { + "noResults": "Нет результатов", + "problems": "Проблемы", + "terminal": "Терминал", + "url": "Вставьте URL для получения содержимого" + }, + "apiConfigSelector": { + "unpin": "Открепить", + "pin": "Закрепить", + "sort": "Сортировать", + "alphabetical": "А–Я", + "custom": "Пользовательский", + "editConfigurations": "Редактировать конфигурации" } } diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 5024290cf2e1..94917ad3ca38 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "Введите имя профиля", "createProfile": "Создать профиль", "cannotDeleteOnlyProfile": "Нельзя удалить единственный профиль", + "exitReorderMode": "Выйти из режима переупорядочивания", + "reorderProfiles": "Переупорядочить профили", + "noConfigs": "Профили конфигурации не найдены", + "reorderModeHelpText": "Используйте Alt/Option + клавиши стрелок для переупорядочивания профилей, или перетащите их", + "normalModeHelpText": "Нажмите на профиль, чтобы выбрать его, или используйте кнопки действий для управления профилями", "searchPlaceholder": "Поиск профилей", "searchProviderPlaceholder": "Поиск провайдеров", "noProviderMatchFound": "Провайдеры не найдены", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index 9b92b937a799..e208c8e87989 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Görevi Roo Code Cloud'da aç", "openInCloudIntro": "Roo'yu her yerden izlemeye veya etkileşime devam et. Açmak için tara, tıkla veya kopyala." }, - "unpin": "Sabitlemeyi iptal et", - "pin": "Sabitle", "tokenProgress": { "availableSpace": "Kullanılabilir alan: {{amount}} token", "tokensUsed": "Kullanılan tokenlar: {{used}} / {{total}}", @@ -428,7 +426,21 @@ "clickToEdit": "Mesajı düzenlemek için tıkla" }, "slashCommand": { - "wantsToRun": "Roo bir slash komutu çalıştırmak istiyor", - "didRun": "Roo bir slash komutu çalıştırdı" + "wantsToRun": "Roo bir slash komutu çalıştırmak istiyor:", + "didRun": "Roo bir slash komutu çalıştırdı:" + }, + "contextMenu": { + "noResults": "Sonuç yok", + "problems": "Sorunlar", + "terminal": "Terminal", + "url": "İçeriği getirmek için URL'yi yapıştırın" + }, + "apiConfigSelector": { + "unpin": "Sabitlemeyi kaldır", + "pin": "Sabitle", + "sort": "Sırala", + "alphabetical": "A–Z", + "custom": "Özel", + "editConfigurations": "Yapılandırmaları düzenle" } } diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 338d52f19560..544d6814ddd6 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "Profil adını girin", "createProfile": "Profil oluştur", "cannotDeleteOnlyProfile": "Yalnızca tek profili silemezsiniz", + "exitReorderMode": "Yeniden sıralama modundan çık", + "reorderProfiles": "Profilleri yeniden sırala", + "noConfigs": "Yapılandırma profili bulunamadı", + "reorderModeHelpText": "Profilleri yeniden sıralamak için Alt/Option + ok tuşlarını kullanın veya sürükleyip bırakın", + "normalModeHelpText": "Seçmek için bir profile tıklayın veya profilleri yönetmek için eylem düğmelerini kullanın", "searchPlaceholder": "Profilleri ara", "searchProviderPlaceholder": "Sağlayıcıları ara", "noProviderMatchFound": "Eşleşen sağlayıcı bulunamadı", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index 39cb1cf01663..4a7d7269a74a 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -28,8 +28,6 @@ "openInCloud": "Mở tác vụ trong Roo Code Cloud", "openInCloudIntro": "Tiếp tục theo dõi hoặc tương tác với Roo từ bất cứ đâu. Quét, nhấp hoặc sao chép để mở." }, - "unpin": "Bỏ ghim khỏi đầu", - "pin": "Ghim lên đầu", "tokenProgress": { "availableSpace": "Không gian khả dụng: {{amount}} tokens", "tokensUsed": "Tokens đã sử dụng: {{used}} trong {{total}}", @@ -428,7 +426,21 @@ "clickToEdit": "Nhấp để chỉnh sửa tin nhắn" }, "slashCommand": { - "wantsToRun": "Roo muốn chạy lệnh slash", - "didRun": "Roo đã chạy lệnh slash" + "wantsToRun": "Roo muốn chạy lệnh slash:", + "didRun": "Roo đã chạy lệnh slash:" + }, + "contextMenu": { + "noResults": "Không có kết quả", + "problems": "Vấn đề", + "terminal": "Terminal", + "url": "Dán URL để lấy nội dung" + }, + "apiConfigSelector": { + "unpin": "Bỏ ghim", + "pin": "Ghim", + "sort": "Sắp xếp", + "alphabetical": "A–Z", + "custom": "Tùy chỉnh", + "editConfigurations": "Chỉnh sửa cấu hình" } } diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 3df608458b15..daa533cfcb8a 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "Nhập tên hồ sơ", "createProfile": "Tạo hồ sơ", "cannotDeleteOnlyProfile": "Không thể xóa hồ sơ duy nhất", + "exitReorderMode": "Thoát chế độ sắp xếp lại", + "reorderProfiles": "Sắp xếp lại hồ sơ", + "noConfigs": "Không tìm thấy hồ sơ cấu hình", + "reorderModeHelpText": "Sử dụng Alt/Option + phím mũi tên để sắp xếp lại hồ sơ, hoặc kéo và thả chúng", + "normalModeHelpText": "Nhấp vào hồ sơ để chọn, hoặc sử dụng các nút hành động để quản lý hồ sơ", "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", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index ef87b819ea99..14d7c82822b1 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -28,8 +28,6 @@ "openInCloud": "在 Roo Code Cloud 中打开任务", "openInCloudIntro": "从任何地方继续监控或与 Roo 交互。扫描、点击或复制以打开。" }, - "unpin": "取消置顶", - "pin": "置顶", "tokenProgress": { "availableSpace": "可用: {{amount}}", "tokensUsed": "已使用: {{used}} / {{total}}", @@ -428,7 +426,21 @@ "clickToEdit": "点击编辑消息" }, "slashCommand": { - "wantsToRun": "Roo 想要运行斜杠命令", - "didRun": "Roo 运行了斜杠命令" + "wantsToRun": "Roo 想要运行斜杠命令:", + "didRun": "Roo 运行了斜杠命令:" + }, + "contextMenu": { + "noResults": "无结果", + "problems": "问题", + "terminal": "终端", + "url": "粘贴URL以获取内容" + }, + "apiConfigSelector": { + "unpin": "取消置顶", + "pin": "置顶", + "sort": "排序", + "alphabetical": "A–Z", + "custom": "自定义", + "editConfigurations": "编辑配置" } } diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index a1afc6f5963e..4036da60144f 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "输入新配置名称", "createProfile": "创建配置", "cannotDeleteOnlyProfile": "无法删除唯一的配置文件", + "exitReorderMode": "退出重新排序模式", + "reorderProfiles": "重新排序配置文件", + "noConfigs": "未找到配置文件", + "reorderModeHelpText": "使用 Alt/Option + 方向键重新排序配置文件,或拖放它们", + "normalModeHelpText": "点击配置文件进行选择,或使用操作按钮管理配置文件", "searchPlaceholder": "搜索配置文件", "searchProviderPlaceholder": "搜索提供商", "noProviderMatchFound": "未找到提供商", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 985859bec418..f5b2e176a0e4 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -28,8 +28,6 @@ "openInCloud": "在 Roo Code Cloud 中開啟工作", "openInCloudIntro": "從任何地方繼續監控或與 Roo 互動。掃描、點擊或複製以開啟。" }, - "unpin": "取消釘選", - "pin": "釘選", "retry": { "title": "重試", "tooltip": "再次嘗試操作" @@ -428,7 +426,21 @@ "clickToEdit": "點選以編輯訊息" }, "slashCommand": { - "wantsToRun": "Roo 想要執行斜線指令", - "didRun": "Roo 執行了斜線指令" + "wantsToRun": "Roo 想要執行斜線指令:", + "didRun": "Roo 執行了斜線指令:" + }, + "contextMenu": { + "noResults": "沒有結果", + "problems": "問題", + "terminal": "終端機", + "url": "貼上 URL 以擷取內容" + }, + "apiConfigSelector": { + "unpin": "取消釘選", + "pin": "釘選", + "sort": "排序", + "alphabetical": "A–Z", + "custom": "自訂", + "editConfigurations": "編輯設定" } } diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index abc31b6bb355..d7600714585d 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -238,6 +238,11 @@ "enterProfileName": "輸入設定檔名稱", "createProfile": "建立設定檔", "cannotDeleteOnlyProfile": "無法刪除唯一的設定檔", + "exitReorderMode": "退出重新排序模式", + "reorderProfiles": "重新排序設定檔", + "noConfigs": "找不到設定檔", + "reorderModeHelpText": "使用 Alt/Option + 方向鍵重新排序設定檔,或拖放它們", + "normalModeHelpText": "點擊設定檔進行選擇,或使用操作按鈕管理設定檔", "searchPlaceholder": "搜尋設定檔", "searchProviderPlaceholder": "搜尋供應商", "noProviderMatchFound": "找不到供應商",