diff --git a/apps/vscode-e2e/src/suite/extension.test.ts b/apps/vscode-e2e/src/suite/extension.test.ts index e7a92521cf6..5d59e003eff 100644 --- a/apps/vscode-e2e/src/suite/extension.test.ts +++ b/apps/vscode-e2e/src/suite/extension.test.ts @@ -15,8 +15,6 @@ suite("Roo Code Extension", function () { "SidebarProvider.removeView", "activationCompleted", "plusButtonClicked", - "mcpButtonClicked", - "promptsButtonClicked", "popoutButtonClicked", "openInNewTab", "settingsButtonClicked", diff --git a/packages/types/src/vscode.ts b/packages/types/src/vscode.ts index d22ebdab229..98a633671c4 100644 --- a/packages/types/src/vscode.ts +++ b/packages/types/src/vscode.ts @@ -30,8 +30,6 @@ export const commandIds = [ "activationCompleted", "plusButtonClicked", - "promptsButtonClicked", - "mcpButtonClicked", "historyButtonClicked", "marketplaceButtonClicked", "popoutButtonClicked", diff --git a/src/activate/registerCommands.ts b/src/activate/registerCommands.ts index 41c127333d8..ad75642406c 100644 --- a/src/activate/registerCommands.ts +++ b/src/activate/registerCommands.ts @@ -101,28 +101,6 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt // This ensures the focus happens after the view has switched await visibleProvider.postMessageToWebview({ type: "action", action: "focusInput" }) }, - mcpButtonClicked: () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) - - if (!visibleProvider) { - return - } - - TelemetryService.instance.captureTitleButtonClicked("mcp") - - visibleProvider.postMessageToWebview({ type: "action", action: "mcpButtonClicked" }) - }, - promptsButtonClicked: () => { - const visibleProvider = getVisibleProviderOrLog(outputChannel) - - if (!visibleProvider) { - return - } - - TelemetryService.instance.captureTitleButtonClicked("prompts") - - visibleProvider.postMessageToWebview({ type: "action", action: "promptsButtonClicked" }) - }, popoutButtonClicked: () => { TelemetryService.instance.captureTitleButtonClicked("popout") diff --git a/src/package.json b/src/package.json index ca8e6e8c148..2f501463f5b 100644 --- a/src/package.json +++ b/src/package.json @@ -75,16 +75,6 @@ "title": "%command.newTask.title%", "icon": "$(edit)" }, - { - "command": "roo-cline.promptsButtonClicked", - "title": "%command.prompts.title%", - "icon": "$(organization)" - }, - { - "command": "roo-cline.mcpButtonClicked", - "title": "%command.mcpServers.title%", - "icon": "$(server)" - }, { "command": "roo-cline.historyButtonClicked", "title": "%command.history.title%", @@ -229,17 +219,17 @@ "when": "view == roo-cline.SidebarProvider" }, { - "command": "roo-cline.marketplaceButtonClicked", + "command": "roo-cline.settingsButtonClicked", "group": "navigation@2", "when": "view == roo-cline.SidebarProvider" }, { - "command": "roo-cline.settingsButtonClicked", + "command": "roo-cline.cloudButtonClicked", "group": "navigation@3", "when": "view == roo-cline.SidebarProvider" }, { - "command": "roo-cline.cloudButtonClicked", + "command": "roo-cline.marketplaceButtonClicked", "group": "navigation@4", "when": "view == roo-cline.SidebarProvider" }, @@ -248,19 +238,9 @@ "group": "overflow@1", "when": "view == roo-cline.SidebarProvider" }, - { - "command": "roo-cline.promptsButtonClicked", - "group": "overflow@2", - "when": "view == roo-cline.SidebarProvider" - }, - { - "command": "roo-cline.mcpButtonClicked", - "group": "overflow@3", - "when": "view == roo-cline.SidebarProvider" - }, { "command": "roo-cline.popoutButtonClicked", - "group": "overflow@4", + "group": "overflow@2", "when": "view == roo-cline.SidebarProvider" } ], @@ -271,17 +251,17 @@ "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, { - "command": "roo-cline.marketplaceButtonClicked", + "command": "roo-cline.settingsButtonClicked", "group": "navigation@2", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, { - "command": "roo-cline.settingsButtonClicked", + "command": "roo-cline.cloudButtonClicked", "group": "navigation@3", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, { - "command": "roo-cline.cloudButtonClicked", + "command": "roo-cline.marketplaceButtonClicked", "group": "navigation@4", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, @@ -290,19 +270,9 @@ "group": "overflow@1", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" }, - { - "command": "roo-cline.promptsButtonClicked", - "group": "overflow@2", - "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" - }, - { - "command": "roo-cline.mcpButtonClicked", - "group": "overflow@3", - "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" - }, { "command": "roo-cline.popoutButtonClicked", - "group": "overflow@4", + "group": "overflow@2", "when": "activeWebviewPanelId == roo-cline.TabPanelProvider" } ] diff --git a/src/package.nls.ca.json b/src/package.nls.ca.json index 22d3f633a64..58d0287423f 100644 --- a/src/package.nls.ca.json +++ b/src/package.nls.ca.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "Servidors MCP", - "command.prompts.title": "Modes", - "command.history.title": "Historial", + "command.history.title": "Historial de Tasques", "command.marketplace.title": "Mercat", "command.openInEditor.title": "Obrir a l'Editor", "command.cloud.title": "Cloud", diff --git a/src/package.nls.de.json b/src/package.nls.de.json index 3931ba000ef..c7266008dea 100644 --- a/src/package.nls.de.json +++ b/src/package.nls.de.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "MCP Server", - "command.prompts.title": "Modi", - "command.history.title": "Verlauf", + "command.history.title": "Aufgabenverlauf", "command.marketplace.title": "Marktplatz", "command.openInEditor.title": "Im Editor Öffnen", "command.cloud.title": "Cloud", diff --git a/src/package.nls.es.json b/src/package.nls.es.json index 0c22cdf9045..1f72ec8db53 100644 --- a/src/package.nls.es.json +++ b/src/package.nls.es.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "Servidores MCP", - "command.prompts.title": "Modos", - "command.history.title": "Historial", + "command.history.title": "Historial de Tareas", "command.marketplace.title": "Mercado", "command.openInEditor.title": "Abrir en Editor", "command.cloud.title": "Cloud", diff --git a/src/package.nls.fr.json b/src/package.nls.fr.json index 422db278202..08c1341d8c1 100644 --- a/src/package.nls.fr.json +++ b/src/package.nls.fr.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "Serveurs MCP", - "command.prompts.title": "Modes", - "command.history.title": "Historique", + "command.history.title": "Historique des Tâches", "command.marketplace.title": "Marché", "command.openInEditor.title": "Ouvrir dans l'Éditeur", "command.cloud.title": "Cloud", diff --git a/src/package.nls.hi.json b/src/package.nls.hi.json index 6337e9e1a33..c67bc5aeb1d 100644 --- a/src/package.nls.hi.json +++ b/src/package.nls.hi.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "एमसीपी सर्वर", - "command.prompts.title": "मोड्स", - "command.history.title": "इतिहास", + "command.history.title": "कार्य इतिहास", "command.marketplace.title": "मार्केटप्लेस", "command.openInEditor.title": "एडिटर में खोलें", "command.cloud.title": "Cloud", diff --git a/src/package.nls.id.json b/src/package.nls.id.json index 1c3025a09d0..8973ef3d404 100644 --- a/src/package.nls.id.json +++ b/src/package.nls.id.json @@ -6,9 +6,7 @@ "views.activitybar.title": "Roo Code", "views.sidebar.name": "Roo Code", "command.newTask.title": "Tugas Baru", - "command.mcpServers.title": "Server MCP", - "command.prompts.title": "Mode", - "command.history.title": "Riwayat", + "command.history.title": "Riwayat Tugas", "command.marketplace.title": "Marketplace", "command.openInEditor.title": "Buka di Editor", "command.cloud.title": "Cloud", diff --git a/src/package.nls.it.json b/src/package.nls.it.json index d0c130e00b1..f9db9769952 100644 --- a/src/package.nls.it.json +++ b/src/package.nls.it.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "Server MCP", - "command.prompts.title": "Modi", - "command.history.title": "Cronologia", + "command.history.title": "Cronologia Attività", "command.marketplace.title": "Marketplace", "command.openInEditor.title": "Apri nell'Editor", "command.cloud.title": "Cloud", diff --git a/src/package.nls.ja.json b/src/package.nls.ja.json index 05251f4aed1..55db11397f1 100644 --- a/src/package.nls.ja.json +++ b/src/package.nls.ja.json @@ -6,9 +6,7 @@ "views.activitybar.title": "Roo Code", "views.sidebar.name": "Roo Code", "command.newTask.title": "新しいタスク", - "command.mcpServers.title": "MCPサーバー", - "command.prompts.title": "モード", - "command.history.title": "履歴", + "command.history.title": "タスク履歴", "command.marketplace.title": "マーケットプレイス", "command.openInEditor.title": "エディタで開く", "command.cloud.title": "Cloud", diff --git a/src/package.nls.json b/src/package.nls.json index 42443e1716d..4d3520d3319 100644 --- a/src/package.nls.json +++ b/src/package.nls.json @@ -6,9 +6,7 @@ "views.activitybar.title": "Roo Code", "views.sidebar.name": "Roo Code", "command.newTask.title": "New Task", - "command.mcpServers.title": "MCP Servers", - "command.prompts.title": "Modes", - "command.history.title": "History", + "command.history.title": "Task History", "command.marketplace.title": "Marketplace", "command.openInEditor.title": "Open in Editor", "command.cloud.title": "Cloud", diff --git a/src/package.nls.ko.json b/src/package.nls.ko.json index dd933733f78..c649d96d139 100644 --- a/src/package.nls.ko.json +++ b/src/package.nls.ko.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "MCP 서버", - "command.prompts.title": "모드", - "command.history.title": "기록", + "command.history.title": "작업 기록", "command.marketplace.title": "마켓플레이스", "command.openInEditor.title": "에디터에서 열기", "command.cloud.title": "Cloud", diff --git a/src/package.nls.nl.json b/src/package.nls.nl.json index c5f52e55712..d4022eae716 100644 --- a/src/package.nls.nl.json +++ b/src/package.nls.nl.json @@ -6,9 +6,7 @@ "views.activitybar.title": "Roo Code", "views.sidebar.name": "Roo Code", "command.newTask.title": "Nieuwe Taak", - "command.mcpServers.title": "MCP Servers", - "command.prompts.title": "Modi", - "command.history.title": "Geschiedenis", + "command.history.title": "Taakgeschiedenis", "command.marketplace.title": "Marktplaats", "command.openInEditor.title": "Openen in Editor", "command.cloud.title": "Cloud", diff --git a/src/package.nls.pl.json b/src/package.nls.pl.json index 1178336d684..690438e454f 100644 --- a/src/package.nls.pl.json +++ b/src/package.nls.pl.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "Serwery MCP", - "command.prompts.title": "Tryby", - "command.history.title": "Historia", + "command.history.title": "Historia Zadań", "command.marketplace.title": "Marketplace", "command.openInEditor.title": "Otwórz w Edytorze", "command.cloud.title": "Cloud", diff --git a/src/package.nls.pt-BR.json b/src/package.nls.pt-BR.json index dfed1c8fb13..37b9d88fad8 100644 --- a/src/package.nls.pt-BR.json +++ b/src/package.nls.pt-BR.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "Servidores MCP", - "command.prompts.title": "Modos", - "command.history.title": "Histórico", + "command.history.title": "Histórico de Tarefas", "command.marketplace.title": "Marketplace", "command.openInEditor.title": "Abrir no Editor", "command.cloud.title": "Cloud", diff --git a/src/package.nls.ru.json b/src/package.nls.ru.json index c2284af3695..0feac79e0c4 100644 --- a/src/package.nls.ru.json +++ b/src/package.nls.ru.json @@ -6,9 +6,7 @@ "views.activitybar.title": "Roo Code", "views.sidebar.name": "Roo Code", "command.newTask.title": "Новая задача", - "command.mcpServers.title": "MCP серверы", - "command.prompts.title": "Режимы", - "command.history.title": "История", + "command.history.title": "История задач", "command.marketplace.title": "Маркетплейс", "command.openInEditor.title": "Открыть в редакторе", "command.cloud.title": "Cloud", diff --git a/src/package.nls.tr.json b/src/package.nls.tr.json index 21d9a1db93b..2cfc82d3f87 100644 --- a/src/package.nls.tr.json +++ b/src/package.nls.tr.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "MCP Sunucuları", - "command.prompts.title": "Modlar", - "command.history.title": "Geçmiş", + "command.history.title": "Görev Geçmişi", "command.marketplace.title": "Marketplace", "command.openInEditor.title": "Düzenleyicide Aç", "command.cloud.title": "Cloud", diff --git a/src/package.nls.vi.json b/src/package.nls.vi.json index 795f8549cf4..0f15b0a546d 100644 --- a/src/package.nls.vi.json +++ b/src/package.nls.vi.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "Máy Chủ MCP", - "command.prompts.title": "Chế Độ", - "command.history.title": "Lịch Sử", + "command.history.title": "Lịch Sử Tác Vụ", "command.marketplace.title": "Marketplace", "command.openInEditor.title": "Mở trong Trình Soạn Thảo", "command.cloud.title": "Cloud", diff --git a/src/package.nls.zh-CN.json b/src/package.nls.zh-CN.json index 1112abab7d6..a9d92a06ea2 100644 --- a/src/package.nls.zh-CN.json +++ b/src/package.nls.zh-CN.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "MCP 服务器", - "command.prompts.title": "模式", - "command.history.title": "历史记录", + "command.history.title": "任务历史记录", "command.marketplace.title": "应用市场", "command.openInEditor.title": "在编辑器中打开", "command.cloud.title": "Cloud", diff --git a/src/package.nls.zh-TW.json b/src/package.nls.zh-TW.json index a212a7a3538..78e5510f5a3 100644 --- a/src/package.nls.zh-TW.json +++ b/src/package.nls.zh-TW.json @@ -19,9 +19,7 @@ "views.contextMenu.label": "Roo Code", "views.terminalMenu.label": "Roo Code", "views.sidebar.name": "Roo Code", - "command.mcpServers.title": "MCP 伺服器", - "command.prompts.title": "模式", - "command.history.title": "歷史記錄", + "command.history.title": "工作歷史記錄", "command.marketplace.title": "應用市場", "command.openInEditor.title": "在編輯器中開啟", "command.cloud.title": "Cloud", diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 53327df7202..b9108fb8e65 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -140,10 +140,8 @@ export interface ExtensionMessage { } action?: | "chatButtonClicked" - | "mcpButtonClicked" | "settingsButtonClicked" | "historyButtonClicked" - | "promptsButtonClicked" | "marketplaceButtonClicked" | "cloudButtonClicked" | "didBecomeVisible" diff --git a/webview-ui/src/App.tsx b/webview-ui/src/App.tsx index f9eb5605c26..62490a11158 100644 --- a/webview-ui/src/App.tsx +++ b/webview-ui/src/App.tsx @@ -17,9 +17,7 @@ import HistoryView from "./components/history/HistoryView" import SettingsView, { SettingsViewRef } from "./components/settings/SettingsView" import WelcomeView from "./components/welcome/WelcomeView" import WelcomeViewProvider from "./components/welcome/WelcomeViewProvider" -import McpView from "./components/mcp/McpView" import { MarketplaceView } from "./components/marketplace/MarketplaceView" -import ModesView from "./components/modes/ModesView" import { HumanRelayDialog } from "./components/human-relay/HumanRelayDialog" import { CheckpointRestoreDialog } from "./components/chat/CheckpointRestoreDialog" import { DeleteMessageDialog, EditMessageDialog } from "./components/chat/MessageModificationConfirmationDialog" @@ -29,7 +27,7 @@ import { useAddNonInteractiveClickListener } from "./components/ui/hooks/useNonI import { TooltipProvider } from "./components/ui/tooltip" import { STANDARD_TOOLTIP_DELAY } from "./components/ui/standard-tooltip" -type Tab = "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "cloud" +type Tab = "settings" | "history" | "chat" | "marketplace" | "cloud" interface HumanRelayDialogState { isOpen: boolean @@ -60,8 +58,6 @@ const MemoizedHumanRelayDialog = React.memo(HumanRelayDialog) const tabsByMessageAction: Partial, Tab>> = { chatButtonClicked: "chat", settingsButtonClicked: "settings", - promptsButtonClicked: "modes", - mcpButtonClicked: "mcp", historyButtonClicked: "history", marketplaceButtonClicked: "marketplace", cloudButtonClicked: "cloud", @@ -271,8 +267,6 @@ const App = () => { ) ) : ( <> - {tab === "modes" && switchTab("chat")} />} - {tab === "mcp" && switchTab("chat")} />} {tab === "history" && switchTab("chat")} />} {tab === "settings" && ( setTab("chat")} targetSection={currentSection} /> diff --git a/webview-ui/src/__tests__/App.spec.tsx b/webview-ui/src/__tests__/App.spec.tsx index 09db361c126..e62f13f938e 100644 --- a/webview-ui/src/__tests__/App.spec.tsx +++ b/webview-ui/src/__tests__/App.spec.tsx @@ -69,23 +69,15 @@ vi.mock("@src/components/history/HistoryView", () => ({ vi.mock("@src/components/mcp/McpView", () => ({ __esModule: true, - default: function McpView({ onDone }: { onDone: () => void }) { - return ( -
- MCP View -
- ) + default: function McpView() { + return
MCP View
}, })) vi.mock("@src/components/modes/ModesView", () => ({ __esModule: true, - default: function ModesView({ onDone }: { onDone: () => void }) { - return ( -
- Modes View -
- ) + default: function ModesView() { + return
Modes View
}, })) @@ -253,34 +245,6 @@ describe("App", () => { expect(chatView.getAttribute("data-hidden")).toBe("true") }) - it("switches to MCP view when receiving mcpButtonClicked action", async () => { - render() - - act(() => { - triggerMessage("mcpButtonClicked") - }) - - const mcpView = await screen.findByTestId("mcp-view") - expect(mcpView).toBeInTheDocument() - - const chatView = screen.getByTestId("chat-view") - expect(chatView.getAttribute("data-hidden")).toBe("true") - }) - - it("switches to prompts view when receiving promptsButtonClicked action", async () => { - render() - - act(() => { - triggerMessage("promptsButtonClicked") - }) - - const promptsView = await screen.findByTestId("prompts-view") - expect(promptsView).toBeInTheDocument() - - const chatView = screen.getByTestId("chat-view") - expect(chatView.getAttribute("data-hidden")).toBe("true") - }) - it("returns to chat view when clicking done in settings view", async () => { render() @@ -299,7 +263,7 @@ describe("App", () => { expect(screen.queryByTestId("settings-view")).not.toBeInTheDocument() }) - it.each(["history", "mcp", "prompts"])("returns to chat view when clicking done in %s view", async (view) => { + it.each(["history"])("returns to chat view when clicking done in %s view", async (view) => { render() act(() => { diff --git a/webview-ui/src/components/chat/ModeSelector.tsx b/webview-ui/src/components/chat/ModeSelector.tsx index 3f843344a22..8810850fad9 100644 --- a/webview-ui/src/components/chat/ModeSelector.tsx +++ b/webview-ui/src/components/chat/ModeSelector.tsx @@ -306,7 +306,11 @@ export const ModeSelector = ({ iconClass="codicon-settings-gear" title={t("chat:modeSelector.settings")} onClick={() => { - vscode.postMessage({ type: "switchTab", tab: "modes" }) + vscode.postMessage({ + type: "switchTab", + tab: "settings", + values: { section: "modes" }, + }) setOpen(false) }} /> diff --git a/webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx b/webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx index b7e9951b0fa..eaf3549781c 100644 --- a/webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx +++ b/webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx @@ -195,25 +195,14 @@ export const MarketplaceInstallModal: React.FC = ( } const handlePostInstallAction = (tab: "mcp" | "modes") => { - if (tab === "mcp") { - // Navigate to MCP tab - window.postMessage( - { - type: "action", - action: "mcpButtonClicked", - }, - "*", - ) - } else { - // Navigate to Modes tab - window.postMessage( - { - type: "action", - action: "promptsButtonClicked", - }, - "*", - ) - } + const section = tab === "mcp" ? "mcp" : "modes" + + vscode.postMessage({ + type: "switchTab", + tab: "settings", + values: { section }, + }) + // Close the modal onClose() } diff --git a/webview-ui/src/components/mcp/McpView.tsx b/webview-ui/src/components/mcp/McpView.tsx index 6f6b752ba89..7c22ad60f85 100644 --- a/webview-ui/src/components/mcp/McpView.tsx +++ b/webview-ui/src/components/mcp/McpView.tsx @@ -7,6 +7,7 @@ import { VSCodePanelTab, VSCodePanelView, } from "@vscode/webview-ui-toolkit/react" +import { Webhook } from "lucide-react" import { McpServer } from "@roo/mcp" @@ -25,19 +26,17 @@ import { StandardTooltip, } from "@src/components/ui" import { buildDocLink } from "@src/utils/docLinks" +import { Section } from "@src/components/settings/Section" +import { SectionHeader } from "@src/components/settings/SectionHeader" -import { Tab, TabContent, TabHeader } from "../common/Tab" +import { TabContent } from "../common/Tab" import McpToolRow from "./McpToolRow" import McpResourceRow from "./McpResourceRow" import McpEnabledToggle from "./McpEnabledToggle" import { McpErrorRow } from "./McpErrorRow" -type McpViewProps = { - onDone: () => void -} - -const McpView = ({ onDone }: McpViewProps) => { +const McpView = () => { const { mcpServers: servers, alwaysAllowMcp, @@ -49,150 +48,156 @@ const McpView = ({ onDone }: McpViewProps) => { const { t } = useAppTranslation() return ( - - -

{t("mcp:title")}

- -
- - -
- - - Learn More - - +
+ +
+ +
{t("mcp:title")}
+
- +
+ +
+ + + Learn More + + +
- {mcpEnabled && ( - <> -
- { - setEnableMcpServerCreation(e.target.checked) - vscode.postMessage({ type: "enableMcpServerCreation", bool: e.target.checked }) - }}> - {t("mcp:enableServerCreation.title")} - -
- - - Learn about server creation - - new - -

{t("mcp:enableServerCreation.hint")}

-
-
+ - {/* Server List */} - {servers.length > 0 && ( -
- {servers.map((server) => ( - - ))} + {mcpEnabled && ( + <> +
+ { + setEnableMcpServerCreation(e.target.checked) + vscode.postMessage({ type: "enableMcpServerCreation", bool: e.target.checked }) + }}> + {t("mcp:enableServerCreation.title")} + +
+ + + Learn about server creation + + new + +

{t("mcp:enableServerCreation.hint")}

+
- )} - {/* Edit Settings Buttons */} -
- - - - - -
-
- - {t("mcp:learnMoreEditingSettings")} - -
- - )} - - + + + + + +
+
+ + {t("mcp:learnMoreEditingSettings")} + +
+ + )} +
+
+
) } diff --git a/webview-ui/src/components/modes/ModesView.tsx b/webview-ui/src/components/modes/ModesView.tsx index b0091c15b7d..dc9522bc44e 100644 --- a/webview-ui/src/components/modes/ModesView.tsx +++ b/webview-ui/src/components/modes/ModesView.tsx @@ -8,7 +8,7 @@ import { VSCodeTextField, } from "@vscode/webview-ui-toolkit/react" import { Trans } from "react-i18next" -import { ChevronDown, X, Upload, Download } from "lucide-react" +import { ChevronDown, X, Upload, Download, MessageSquare } from "lucide-react" import { ModeConfig, GroupEntry, PromptComponent, ToolGroup, modeConfigSchema } from "@roo-code/types" @@ -28,7 +28,9 @@ import { vscode } from "@src/utils/vscode" import { buildDocLink } from "@src/utils/docLinks" import { useAppTranslation } from "@src/i18n/TranslationContext" import { useExtensionState } from "@src/context/ExtensionStateContext" -import { Tab, TabContent, TabHeader } from "@src/components/common/Tab" +import { Section } from "@src/components/settings/Section" +import { SectionHeader } from "@src/components/settings/SectionHeader" +import { TabContent } from "@src/components/common/Tab" import { Button, Select, @@ -58,16 +60,12 @@ type ModeSource = "global" | "project" type ImportModeResult = { type: "importModeResult"; success: boolean; slug?: string; error?: string } -type ModesViewProps = { - onDone: () => void -} - // Helper to get group name regardless of format function getGroupName(group: GroupEntry): ToolGroup { return Array.isArray(group) ? group[0] : group } -const ModesView = ({ onDone }: ModesViewProps) => { +const ModesView = () => { const { t } = useAppTranslation() const { @@ -595,874 +593,890 @@ const ModesView = ({ onDone }: ModesViewProps) => { } return ( - - -

{t("prompts:title")}

- -
- - -
-
e.stopPropagation()} className="flex justify-between items-center mb-3"> -

{t("prompts:modes.title")}

-
-
- - - - {showConfigMenu && ( -
e.stopPropagation()} - onMouseDown={(e) => e.stopPropagation()} - className="absolute top-full right-0 w-[200px] mt-1 bg-vscode-editor-background border border-vscode-input-border rounded shadow-md z-[1000]"> -
{ - e.preventDefault() // Prevent blur - vscode.postMessage({ - type: "openCustomModesSettings", - }) - setShowConfigMenu(false) +
+ +
+ +
{t("prompts:title")}
+
+
+ +
+ +
+
e.stopPropagation()} className="flex justify-between items-center mb-3"> +

{t("prompts:modes.title")}

+
+
+ +
+ onBlur={() => { + // Add slight delay to allow menu item clicks to register + setTimeout(() => setShowConfigMenu(false), 200) + }}> + + + + {showConfigMenu && (
{ - e.preventDefault() // Prevent blur - vscode.postMessage({ - type: "openFile", - text: "./.roomodes", - values: { - create: true, - content: JSON.stringify({ customModes: [] }, null, 2), - }, - }) - setShowConfigMenu(false) - }} - onClick={(e) => e.preventDefault()}> - {t("prompts:modes.editProjectModes")} + onClick={(e) => e.stopPropagation()} + onMouseDown={(e) => e.stopPropagation()} + className="absolute top-full right-0 w-[200px] mt-1 bg-vscode-editor-background border border-vscode-input-border rounded shadow-md z-[1000]"> +
{ + e.preventDefault() // Prevent blur + vscode.postMessage({ + type: "openCustomModesSettings", + }) + setShowConfigMenu(false) + }} + onClick={(e) => e.preventDefault()}> + {t("prompts:modes.editGlobalModes")} +
+
{ + e.preventDefault() // Prevent blur + vscode.postMessage({ + type: "openFile", + text: "./.roomodes", + values: { + create: true, + content: JSON.stringify({ customModes: [] }, null, 2), + }, + }) + setShowConfigMenu(false) + }} + onClick={(e) => e.preventDefault()}> + {t("prompts:modes.editProjectModes")} +
-
- )} -
- - - - - - - -
-
- -
- - - - -
- -
- {isRenamingMode ? ( - <> - { - const target = e as { target: { value: string } } - setRenameInputValue(target.target.value) - }} - className="grow" - placeholder={t("prompts:createModeDialog.name.placeholder")} - /> - + )} +
+ - + + - - ) : ( - <> - - +
+
+ +
+ + + + +
+ +
+ {isRenamingMode ? ( + <> + { + const target = e as { target: { value: string } } + setRenameInputValue(target.target.value) + }} + className="grow" + placeholder={t("prompts:createModeDialog.name.placeholder")} + /> + - - - -
- - {searchValue.length > 0 && ( -
- -
- )} -
- - - {searchValue && ( -
- {t("prompts:modes.noMatchFound")} + + + + + + ) : ( + <> + + + + + + +
+ + {searchValue.length > 0 && ( +
+
)} - - - {displayModes - .filter((modeConfig) => - searchValue - ? modeConfig.name - .toLowerCase() - .includes(searchValue.toLowerCase()) - : true, - ) - .map((modeConfig) => ( - { - handleModeSwitch(modeConfig) - setOpen(false) - }} - data-testid={`mode-option-${modeConfig.slug}`}> -
- - {modeConfig.name} - - - {modeConfig.slug} - -
-
- ))} -
- - - - - - {/* New mode (+) moved here from the top bar */} - - - +
+ + + {searchValue && ( +
+ {t("prompts:modes.noMatchFound")} +
+ )} +
+ + {displayModes + .filter((modeConfig) => + searchValue + ? modeConfig.name + .toLowerCase() + .includes(searchValue.toLowerCase()) + : true, + ) + .map((modeConfig) => ( + { + handleModeSwitch(modeConfig) + setOpen(false) + }} + data-testid={`mode-option-${modeConfig.slug}`}> +
+ + {modeConfig.name} + + + {modeConfig.slug} + +
+
+ ))} +
+
+
+
+
+ + {/* New mode (+) moved here from the top bar */} + + + - {/* Edit (rename) mode - only enabled for custom modes */} - + {/* Edit (rename) mode - only enabled for custom modes */} + + + + + {/* Delete mode - disabled for built-in modes */} + + + + + {/* Export mode (kept here to the right of the dropdown) */} + + + + + )} +
+ + {/* API Configuration - Moved Here */} +
+
{t("prompts:apiConfiguration.title")}
+
+ {t("prompts:apiConfiguration.select")} +
+
+ +
+
+
+ + {/* Role Definition section */} +
+
+
{t("prompts:roleDefinition.title")}
+ {!findModeBySlug(visualMode, customModes) && ( + + )} +
+
+ {t("prompts:roleDefinition.description")} +
+ { + const customMode = findModeBySlug(visualMode, customModes) + const prompt = customModePrompts?.[visualMode] as PromptComponent + return ( + customMode?.roleDefinition ?? + prompt?.roleDefinition ?? + getRoleDefinition(visualMode) + ) + })()} + onChange={(e) => { + const value = + (e as unknown as CustomEvent)?.detail?.target?.value ?? + ((e as any).target as HTMLTextAreaElement).value + const customMode = findModeBySlug(visualMode, customModes) + if (customMode) { + // For custom modes, update the JSON file + updateCustomMode(visualMode, { + ...customMode, + roleDefinition: value.trim() || "", + source: customMode.source || "global", + }) + } else { + // For built-in modes, update the prompts + updateAgentPrompt(visualMode, { + roleDefinition: value.trim() || undefined, + }) + } + }} + className="w-full" + rows={5} + data-testid={`${getCurrentMode()?.slug || "code"}-prompt-textarea`} + /> +
- {/* Delete mode - disabled for built-in modes */} - + {/* Description section */} +
+
+
{t("prompts:description.title")}
+ {!findModeBySlug(visualMode, customModes) && ( + + )} +
+
+ {t("prompts:description.description")} +
+ { + const customMode = findModeBySlug(visualMode, customModes) + const prompt = customModePrompts?.[visualMode] as PromptComponent + return customMode?.description ?? prompt?.description ?? getDescription(visualMode) + })()} + onChange={(e) => { + const value = + (e as unknown as CustomEvent)?.detail?.target?.value ?? + ((e as any).target as HTMLTextAreaElement).value + const customMode = findModeBySlug(visualMode, customModes) + if (customMode) { + // For custom modes, update the JSON file + updateCustomMode(visualMode, { + ...customMode, + description: value.trim() || undefined, + source: customMode.source || "global", + }) + } else { + // For built-in modes, update the prompts + updateAgentPrompt(visualMode, { + description: value.trim() || undefined, + }) + } + }} + className="w-full" + data-testid={`${getCurrentMode()?.slug || "code"}-description-textfield`} + /> +
- {/* Export mode (kept here to the right of the dropdown) */} - + {/* When to Use section */} +
+
+
{t("prompts:whenToUse.title")}
+ {!findModeBySlug(visualMode, customModes) && ( + - - )} -
- - {/* API Configuration - Moved Here */} -
-
{t("prompts:apiConfiguration.title")}
+ )} +
- {t("prompts:apiConfiguration.select")} + {t("prompts:whenToUse.description")}
-
- -
+ } else { + // For built-in modes, update the prompts + updateAgentPrompt(visualMode, { + whenToUse: value.trim() || undefined, + }) + } + }} + className="w-full" + rows={4} + data-testid={`${getCurrentMode()?.slug || "code"}-when-to-use-textarea`} + />
-
- {/* Role Definition section */} -
-
-
{t("prompts:roleDefinition.title")}
- {!findModeBySlug(visualMode, customModes) && ( - - + + )} +
+ {!findModeBySlug(visualMode, customModes) && ( +
+ {t("prompts:tools.builtInModesText")} +
+ )} + {isToolsEditMode && findModeBySlug(visualMode, customModes) ? ( +
+ {availableGroups.map((group) => { const currentMode = getCurrentMode() - if (currentMode?.slug) { - handleAgentReset(currentMode.slug, "roleDefinition") - } - }} - data-testid="role-definition-reset"> - - - - )} -
-
- {t("prompts:roleDefinition.description")} -
- { - const customMode = findModeBySlug(visualMode, customModes) - const prompt = customModePrompts?.[visualMode] as PromptComponent - return customMode?.roleDefinition ?? prompt?.roleDefinition ?? getRoleDefinition(visualMode) - })()} - onChange={(e) => { - const value = - (e as unknown as CustomEvent)?.detail?.target?.value ?? - ((e as any).target as HTMLTextAreaElement).value - const customMode = findModeBySlug(visualMode, customModes) - if (customMode) { - // For custom modes, update the JSON file - updateCustomMode(visualMode, { - ...customMode, - roleDefinition: value.trim() || "", - source: customMode.source || "global", - }) - } else { - // For built-in modes, update the prompts - updateAgentPrompt(visualMode, { - roleDefinition: value.trim() || undefined, - }) - } - }} - className="w-full" - rows={5} - data-testid={`${getCurrentMode()?.slug || "code"}-prompt-textarea`} - /> -
- - {/* Description section */} -
-
-
{t("prompts:description.title")}
- {!findModeBySlug(visualMode, customModes) && ( - -
+ ) : ( +
+ {(() => { const currentMode = getCurrentMode() - if (currentMode?.slug) { - handleAgentReset(currentMode.slug, "description") - } - }} - data-testid="description-reset"> - - - - )} -
-
- {t("prompts:description.description")} -
- { - const customMode = findModeBySlug(visualMode, customModes) - const prompt = customModePrompts?.[visualMode] as PromptComponent - return customMode?.description ?? prompt?.description ?? getDescription(visualMode) - })()} - onChange={(e) => { - const value = - (e as unknown as CustomEvent)?.detail?.target?.value ?? - ((e as any).target as HTMLTextAreaElement).value - const customMode = findModeBySlug(visualMode, customModes) - if (customMode) { - // For custom modes, update the JSON file - updateCustomMode(visualMode, { - ...customMode, - description: value.trim() || undefined, - source: customMode.source || "global", - }) - } else { - // For built-in modes, update the prompts - updateAgentPrompt(visualMode, { - description: value.trim() || undefined, - }) - } - }} - className="w-full" - data-testid={`${getCurrentMode()?.slug || "code"}-description-textfield`} - /> -
+ const enabledGroups = currentMode?.groups || [] - {/* When to Use section */} -
-
-
{t("prompts:whenToUse.title")}
- {!findModeBySlug(visualMode, customModes) && ( - - - - )} -
-
- {t("prompts:whenToUse.description")} -
- { - const customMode = findModeBySlug(visualMode, customModes) - const prompt = customModePrompts?.[visualMode] as PromptComponent - return customMode?.whenToUse ?? prompt?.whenToUse ?? getWhenToUse(visualMode) - })()} - onChange={(e) => { - const value = - (e as unknown as CustomEvent)?.detail?.target?.value ?? - ((e as any).target as HTMLTextAreaElement).value - const customMode = findModeBySlug(visualMode, customModes) - if (customMode) { - // For custom modes, update the JSON file - updateCustomMode(visualMode, { - ...customMode, - whenToUse: value.trim() || undefined, - source: customMode.source || "global", - }) - } else { - // For built-in modes, update the prompts - updateAgentPrompt(visualMode, { - whenToUse: value.trim() || undefined, - }) - } - }} - className="w-full" - rows={4} - data-testid={`${getCurrentMode()?.slug || "code"}-when-to-use-textarea`} - /> -
- {/* Mode settings */} - <> - {/* Show tools for all modes */} -
+ return enabledGroups + .map((group) => { + const groupName = getGroupName(group) + const displayName = t(`prompts:tools.toolNames.${groupName}`) + if (Array.isArray(group) && group[1]?.fileRegex) { + const description = + group[1].description || `/${group[1].fileRegex}/` + return `${displayName} (${description})` + } + return displayName + }) + .join(", ") + })()} +
+ )} +
+ + + {/* Role definition for both built-in and custom modes */} +
-
{t("prompts:tools.title")}
- {findModeBySlug(visualMode, customModes) && ( - +
{t("prompts:customInstructions.title")}
+ {!findModeBySlug(visualMode, customModes) && ( + )}
- {!findModeBySlug(visualMode, customModes) && ( -
- {t("prompts:tools.builtInModesText")} -
- )} - {isToolsEditMode && findModeBySlug(visualMode, customModes) ? ( -
- {availableGroups.map((group) => { - const currentMode = getCurrentMode() - const isCustomMode = findModeBySlug(visualMode, customModes) - const customMode = isCustomMode - const isGroupEnabled = isCustomMode - ? customMode?.groups?.some((g) => getGroupName(g) === group) - : currentMode?.groups?.some((g) => getGroupName(g) === group) - - return ( - - {t(`prompts:tools.toolNames.${group}`)} - {group === "edit" && ( -
- {t("prompts:tools.allowedFiles")}{" "} - {(() => { - const currentMode = getCurrentMode() - const editGroup = currentMode?.groups?.find( - (g) => - Array.isArray(g) && g[0] === "edit" && g[1]?.fileRegex, - ) - if (!Array.isArray(editGroup)) return t("prompts:allFiles") - return editGroup[1].description || `/${editGroup[1].fileRegex}/` - })()} -
- )} -
- ) - })} -
- ) : ( -
- {(() => { - const currentMode = getCurrentMode() - const enabledGroups = currentMode?.groups || [] - - // If there are no enabled groups, display translated "None" - if (enabledGroups.length === 0) { - return t("prompts:tools.noTools") - } - - return enabledGroups - .map((group) => { - const groupName = getGroupName(group) - const displayName = t(`prompts:tools.toolNames.${groupName}`) - if (Array.isArray(group) && group[1]?.fileRegex) { - const description = group[1].description || `/${group[1].fileRegex}/` - return `${displayName} (${description})` - } - return displayName - }) - .join(", ") - })()} -
- )} -
- - - {/* Role definition for both built-in and custom modes */} -
-
-
{t("prompts:customInstructions.title")}
- {!findModeBySlug(visualMode, customModes) && ( - - - - )} -
-
- {t("prompts:customInstructions.description", { - modeName: getCurrentMode()?.name || "Code", - })} -
- { - const customMode = findModeBySlug(visualMode, customModes) - const prompt = customModePrompts?.[visualMode] as PromptComponent - return ( - customMode?.customInstructions ?? - prompt?.customInstructions ?? - getCustomInstructions(visualMode, customModes) - ) - })()} - onChange={(e) => { - const value = - (e as unknown as CustomEvent)?.detail?.target?.value ?? - ((e as any).target as HTMLTextAreaElement).value - const customMode = findModeBySlug(visualMode, customModes) - if (customMode) { - // For custom modes, update the JSON file - updateCustomMode(visualMode, { - ...customMode, - // Preserve empty string; only treat null/undefined as unset - customInstructions: value ?? undefined, - source: customMode.source || "global", - }) - } else { - // For built-in modes, update the prompts - const existingPrompt = customModePrompts?.[visualMode] as PromptComponent - updateAgentPrompt(visualMode, { - ...existingPrompt, - customInstructions: value.trim() || undefined, - }) - } - }} - rows={10} - className="w-full" - data-testid={`${getCurrentMode()?.slug || "code"}-custom-instructions-textarea`} - /> -
- { - const currentMode = getCurrentMode() - if (!currentMode) return - - // Open or create an empty file - vscode.postMessage({ - type: "openFile", - text: `./.roo/rules-${currentMode.slug}/rules.md`, - values: { - create: true, - content: "", - }, - }) - }} - /> - ), - "0": ( - - ), +
+ {t("prompts:customInstructions.description", { + modeName: getCurrentMode()?.name || "Code", + })} +
+ { + const customMode = findModeBySlug(visualMode, customModes) + const prompt = customModePrompts?.[visualMode] as PromptComponent + return ( + customMode?.customInstructions ?? + prompt?.customInstructions ?? + getCustomInstructions(visualMode, customModes) + ) + })()} + onChange={(e) => { + const value = + (e as unknown as CustomEvent)?.detail?.target?.value ?? + ((e as any).target as HTMLTextAreaElement).value + const customMode = findModeBySlug(visualMode, customModes) + if (customMode) { + // For custom modes, update the JSON file + updateCustomMode(visualMode, { + ...customMode, + // Preserve empty string; only treat null/undefined as unset + customInstructions: value ?? undefined, + source: customMode.source || "global", + }) + } else { + // For built-in modes, update the prompts + const existingPrompt = customModePrompts?.[visualMode] as PromptComponent + updateAgentPrompt(visualMode, { + ...existingPrompt, + customInstructions: value.trim() || undefined, + }) + } }} + rows={10} + className="w-full" + data-testid={`${getCurrentMode()?.slug || "code"}-custom-instructions-textarea`} /> +
+ { + const currentMode = getCurrentMode() + if (!currentMode) return + + // Open or create an empty file + vscode.postMessage({ + type: "openFile", + text: `./.roo/rules-${currentMode.slug}/rules.md`, + values: { + create: true, + content: "", + }, + }) + }} + /> + ), + "0": ( + + ), + }} + /> +
-
-
-
- - +
+
- -
+ + + +
- {/* Advanced Features Disclosure */} -
- - - {isSystemPromptDisclosureOpen && ( -
- {/* Override System Prompt Section */} -
-

- Override System Prompt -

-
- { - const currentMode = getCurrentMode() - if (!currentMode) return - - vscode.postMessage({ - type: "openFile", - text: `./.roo/system-prompt-${currentMode.slug}`, - values: { - create: true, - content: "", - }, - }) - }} - /> - ), - "1": ( - - ), - "2": , - }} - /> + {/* Advanced Features Disclosure */} +
+ + + {isSystemPromptDisclosureOpen && ( +
+ {/* Override System Prompt Section */} +
+

+ Override System Prompt +

+
+ { + const currentMode = getCurrentMode() + if (!currentMode) return + + vscode.postMessage({ + type: "openFile", + text: `./.roo/system-prompt-${currentMode.slug}`, + values: { + create: true, + content: "", + }, + }) + }} + /> + ), + "1": ( + + ), + "2": , + }} + /> +
-
- )} + )} +
-
-
-

{t("prompts:globalCustomInstructions.title")}

+
+

{t("prompts:globalCustomInstructions.title")}

-
- - - -
- { - const value = - (e as unknown as CustomEvent)?.detail?.target?.value ?? - ((e as any).target as HTMLTextAreaElement).value - setCustomInstructions(value ?? undefined) - vscode.postMessage({ - type: "customInstructions", - text: value ?? undefined, - }) - }} - rows={4} - className="w-full" - data-testid="global-custom-instructions-textarea" - /> -
- - vscode.postMessage({ - type: "openFile", - text: "./.roo/rules/rules.md", - values: { - create: true, - content: "", - }, - }) - } - /> - ), - "0": ( - - ), +
+ + + +
+ { + const value = + (e as unknown as CustomEvent)?.detail?.target?.value ?? + ((e as any).target as HTMLTextAreaElement).value + setCustomInstructions(value ?? undefined) + vscode.postMessage({ + type: "customInstructions", + text: value ?? undefined, + }) }} + rows={4} + className="w-full" + data-testid="global-custom-instructions-textarea" /> +
+ + vscode.postMessage({ + type: "openFile", + text: "./.roo/rules/rules.md", + values: { + create: true, + content: "", + }, + }) + } + /> + ), + "0": ( + + ), + }} + /> +
-
- + + {isCreateModeDialogOpen && (
@@ -1765,7 +1779,7 @@ const ModesView = ({ onDone }: ModesViewProps) => { } }} /> - +
) } diff --git a/webview-ui/src/components/modes/__tests__/ModesView.import-switch.spec.tsx b/webview-ui/src/components/modes/__tests__/ModesView.import-switch.spec.tsx index b62fc885636..2bd4ea096df 100644 --- a/webview-ui/src/components/modes/__tests__/ModesView.import-switch.spec.tsx +++ b/webview-ui/src/components/modes/__tests__/ModesView.import-switch.spec.tsx @@ -30,10 +30,9 @@ const mockExtensionState = { } const renderModesView = (props = {}) => { - const mockOnDone = vitest.fn() return render( - + , ) } diff --git a/webview-ui/src/components/modes/__tests__/ModesView.spec.tsx b/webview-ui/src/components/modes/__tests__/ModesView.spec.tsx index 1a30ae079f1..25dc7fb8e16 100644 --- a/webview-ui/src/components/modes/__tests__/ModesView.spec.tsx +++ b/webview-ui/src/components/modes/__tests__/ModesView.spec.tsx @@ -29,10 +29,9 @@ const mockExtensionState = { } const renderPromptsView = (props = {}) => { - const mockOnDone = vitest.fn() return render( - + , ) } @@ -128,7 +127,7 @@ describe("PromptsView", () => { const { unmount } = render( - + , ) @@ -154,7 +153,7 @@ describe("PromptsView", () => { render( - + , ) @@ -175,7 +174,7 @@ describe("PromptsView", () => { const { unmount } = render( - + , ) @@ -190,7 +189,7 @@ describe("PromptsView", () => { render( - + , ) diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index dc1f1ae5ae0..4e0dc638b7f 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -25,6 +25,9 @@ import { LucideIcon, SquareSlash, Glasses, + Plug, + Server, + Users2, } from "lucide-react" import { @@ -74,6 +77,8 @@ import { Section } from "./Section" import PromptsSettings from "./PromptsSettings" import { SlashCommandsSettings } from "./SlashCommandsSettings" import { UISettings } from "./UISettings" +import ModesView from "../modes/ModesView" +import McpView from "../mcp/McpView" export const settingsTabsContainer = "flex flex-1 overflow-hidden [&.narrow_.tab-label]:hidden" export const settingsTabList = @@ -95,6 +100,8 @@ const sectionNames = [ "notifications", "contextManagement", "terminal", + "modes", + "mcp", "prompts", "ui", "experimental", @@ -501,7 +508,9 @@ const SettingsView = forwardRef(({ onDone, t const sections: { id: SectionName; icon: LucideIcon }[] = useMemo( () => [ - { id: "providers", icon: Webhook }, + { id: "providers", icon: Plug }, + { id: "modes", icon: Users2 }, + { id: "mcp", icon: Server }, { id: "autoApprove", icon: CheckCheck }, { id: "slashCommands", icon: SquareSlash }, { id: "browser", icon: SquareMousePointer }, @@ -614,7 +623,7 @@ const SettingsView = forwardRef(({ onDone, t isSelected // Use manual isSelected for styling ? `${settingsTabTrigger} ${settingsTabTriggerActive}` : settingsTabTrigger, - "focus:ring-0", // Remove the focus ring styling + "cursor-pointer focus:ring-0", // Remove the focus ring styling )} data-testid={`tab-${id}`} data-compact={isCompactMode}> @@ -802,6 +811,12 @@ const SettingsView = forwardRef(({ onDone, t /> )} + {/* Modes Section */} + {activeTab === "modes" && } + + {/* MCP Section */} + {activeTab === "mcp" && } + {/* Prompts Section */} {activeTab === "prompts" && (