diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index da1770cd13..efb593792a 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -1,3 +1,4 @@ +// @refresh reload import { AppIcon } from "@opencode-ai/ui/app-icon" import { Button } from "@opencode-ai/ui/button" import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" @@ -235,8 +236,8 @@ export function SessionHeader() { messageAgentColor(params.id ? sync().data.message[params.id] : undefined, sync().data.agent), ) const v2ActionsState = createMemo(() => ({ - statusVisible: status(), - statusLabel: language.t("status.popover.trigger"), + toolsVisible: isDesktop(), + statusLabel: language.t("status.popover.tools.trigger"), reviewLabel: language.t("command.review.toggle"), reviewKeybind: reviewTooltipKeybind(command), reviewVisible: isDesktop(), @@ -517,7 +518,7 @@ export function SessionHeader() { } type SessionHeaderV2ActionsState = { - statusVisible: boolean + toolsVisible: boolean statusLabel: string reviewLabel: string reviewKeybind: string[] @@ -530,11 +531,11 @@ function SessionHeaderV2Actions(props: { state: SessionHeaderV2ActionsState }) { const language = useLanguage() return ( -
- - +
+ + - + { const parts = value.split(file) @@ -280,7 +281,14 @@ export function StatusPopoverBody(props: { shown: Accessor }) { const toggleMcp = useMcpToggle() const defaultServer = useDefaultServerKey(platform.getDefaultServer) const mcpNames = createMemo(() => Object.keys(sync().data.mcp ?? {}).sort((a, b) => a.localeCompare(b))) + const configuredMcpNames = createMemo(() => + Object.keys(sync().data.config.mcp ?? {}).sort((a, b) => a.localeCompare(b)), + ) const mcpStatus = (name: string) => sync().data.mcp?.[name]?.status + const mcpError = (name: string) => { + const status = sync().data.mcp?.[name] + if (status?.status === "failed" || status?.status === "needs_client_registration") return status.error + } const mcpConnected = createMemo(() => mcpNames().filter((name) => mcpStatus(name) === "connected").length) const lspItems = createMemo(() => sync().data.lsp ?? []) const lspCount = createMemo(() => lspItems().length) @@ -289,6 +297,41 @@ export function StatusPopoverBody(props: { shown: Accessor }) { ) const pluginCount = createMemo(() => plugins().length) const pluginEmpty = createMemo(() => pluginEmptyMessage(language.t("dialog.plugins.empty"), "opencode.json")) + if (settings.general.newLayoutDesigns()) { + return ( + ({ + name, + status: mcpStatus(name), + error: mcpError(name), + pending: !mcpStatus(name) || (toggleMcp.isPending && toggleMcp.variables === name), + onToggle: () => { + if (toggleMcp.isPending) return + toggleMcp.mutate(name) + }, + }))} + lsp={lspItems().map((item) => ({ name: item.name || item.id, status: item.status }))} + plugins={plugins()} + /> + ) + } return (
diff --git a/packages/app/src/components/status-popover.tsx b/packages/app/src/components/status-popover.tsx index c75dd5b655..5da65d0852 100644 --- a/packages/app/src/components/status-popover.tsx +++ b/packages/app/src/components/status-popover.tsx @@ -1,7 +1,7 @@ +// @refresh reload import { Button } from "@opencode-ai/ui/button" import { Icon } from "@opencode-ai/ui/icon" import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" import { Popover } from "@opencode-ai/ui/popover" import { Suspense, createMemo, createSignal, lazy, Show, type JSX } from "solid-js" import { useLanguage } from "@/context/language" @@ -9,6 +9,7 @@ import { ServerConnection, useServer } from "@/context/server" import { useServerSDK } from "@/context/server-sdk" import { useSync } from "@/context/sync" import { useGlobal } from "@/context/global" +import { ToolsMenuIcon } from "./tools-menu" const Body = lazy(() => import("./status-popover-body").then((x) => ({ default: x.StatusPopoverBody }))) const ServerBody = lazy(() => import("./status-popover-body").then((x) => ({ default: x.StatusPopoverServerBody }))) @@ -89,7 +90,10 @@ function DirectoryStatusPopover() { const serverHealth = () => global.servers.health[ServerConnection.key(server().server)]?.healthy const ready = createMemo(() => serverHealth() === false || sync().data.mcp_ready) const mcpIssue = createMemo(() => { - const mcp = Object.values(sync().data.mcp ?? {}) + const mcp = Object.keys(sync().data.config.mcp ?? {}).flatMap((name) => { + const status = sync().data.mcp?.[name] + return status ? [status] : [] + }) const failed = mcp.some((item) => item.status === "failed" || item.status === "needs_client_registration") const warn = mcp.some((item) => item.status === "needs_auth") if (failed) return "critical" as const @@ -102,7 +106,7 @@ function DirectoryStatusPopover() { healthy: healthy(), serverHealth: serverHealth(), issue: mcpIssue(), - label: language.t("status.popover.trigger"), + label: language.t("status.popover.tools.trigger"), onOpenChange: setShown, body: () => ( @@ -161,15 +165,7 @@ function StatusPopoverBody(props: { shown: boolean; children: JSX.Element }) { } function StatusPopoverView(props: { state: StatusPopoverState }) { - const statusDotClass = () => ({ - "absolute rounded-full": true, - "bg-icon-success-base": props.state.ready && props.state.healthy, - "bg-icon-warning-base": props.state.ready && props.state.serverHealth === true && props.state.issue === "warning", - "bg-icon-critical-base": - props.state.serverHealth === false || - (props.state.ready && props.state.serverHealth === true && props.state.issue === "critical"), - "bg-border-weak-base": props.state.serverHealth === undefined || !props.state.ready, - }) + const warning = () => props.state.serverHealth === false || props.state.issue !== undefined const popoverProps = { class: @@ -191,15 +187,7 @@ function StatusPopoverView(props: { state: StatusPopoverState }) { state: props.state.shown ? "pressed" : undefined, "aria-label": props.state.label, }} - trigger={ -
- -
-
- } + trigger={} {...popoverProps} > {props.state.body()} diff --git a/packages/app/src/components/tools-menu.tsx b/packages/app/src/components/tools-menu.tsx new file mode 100644 index 0000000000..afbb9077d2 --- /dev/null +++ b/packages/app/src/components/tools-menu.tsx @@ -0,0 +1,200 @@ +import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" +import { Icon } from "@opencode-ai/ui/v2/icon" +import { SegmentedControlItemV2, SegmentedControlV2 } from "@opencode-ai/ui/v2/segmented-control-v2" +import { Switch } from "@opencode-ai/ui/v2/switch-v2" +import { For, Show, type JSXElement } from "solid-js" +import { createStore } from "solid-js/store" + +export type ToolsMenuTab = "mcp" | "lsp" | "plugins" +export type ToolsMenuStatus = "connected" | "failed" | "error" | "needs_auth" | "needs_client_registration" | "disabled" + +export type ToolsMenuProps = { + defaultTab?: ToolsMenuTab + labels: { + menu: string + mcp: string + lsp: string + plugins: string + mcpDescription: string + lspDescription: string + pluginsDescription: string + disabled: string + failed: string + reauthenticate: string + } + empty: { + mcp: JSXElement + lsp: JSXElement + plugins: JSXElement + } + mcp: Array<{ + name: string + status?: ToolsMenuStatus + error?: string + pending?: boolean + onToggle?: () => void + }> + lsp: Array<{ + name: string + status: "connected" | "error" + }> + plugins: string[] +} + +export function ToolsMenuIcon(props: { warning?: boolean }) { + return ( +
+ + +
+ +
+ ) +} + +export function ToolsMenu(props: ToolsMenuProps) { + const [state, setState] = createStore({ tab: props.defaultTab ?? ("mcp" as ToolsMenuTab) }) + + return ( +
+ value && setState("tab", value as ToolsMenuTab)} + class="segmented-control-v2--full-width" + aria-label={props.labels.menu} + > + {props.labels.mcp} + {props.labels.lsp} + {props.labels.plugins} + + + + 0} + fallback={} + > + + + {(item) => ( +
+ + + {item.name} + + + + + {item.error ?? props.labels.failed} + + + + + + {item.status === "disabled" ? props.labels.disabled : props.labels.failed} + + + + {item.name} + + + + } + > + + {props.labels.reauthenticate} + + +
+ )} +
+
+
+
+ + + 0} + fallback={} + > + + + {(item) => ( +
+ + + {item.name} + +
+ )} +
+
+
+
+ + + 0} + fallback={} + > + + + {(plugin) => ( +
+ + + {plugin} + +
+ )} +
+
+
+
+
+ ) +} + +function ToolsList(props: { description: string; children: JSXElement }) { + return ( +
+
+ {props.description} +
+ {props.children} +
+ ) +} + +function ToolsEmpty(props: { title: JSXElement; description: string }) { + return ( +
+
{props.title}
+
{props.description}
+
+ ) +} + +function StatusDot(props: { status?: ToolsMenuStatus }) { + return ( +
+ ) +} diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts index 2b639eded7..6183033162 100644 --- a/packages/app/src/i18n/ar.ts +++ b/packages/app/src/i18n/ar.ts @@ -621,6 +621,14 @@ export const dict = { "session.header.open.menu": "خيارات الفتح", "session.header.open.copyPath": "نسخ المسار", "status.popover.trigger": "الحالة", + "status.popover.tools.trigger": "الأدوات", + "status.popover.tools.mcp.description": "أضف خوادم MCP في opencode.json", + "status.popover.tools.lsp.description": "يتم اكتشاف خوادم LSP تلقائيًا عند فتح الملفات", + "status.popover.tools.plugins.description": "أضف الإضافات في opencode.json", + "status.popover.tools.mcp.empty": "لم يتم إعداد أي خوادم MCP بعد", + "status.popover.tools.lsp.empty": "لا توجد خوادم لغة نشطة بعد", + "status.popover.tools.plugins.empty": "لم يتم إعداد أي إضافات بعد", + "status.popover.tools.reauthenticate": "إعادة المصادقة", "status.popover.ariaLabel": "إعدادات الخوادم", "status.popover.tab.servers": "الخوادم", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts index 688b05fee1..75c7d0860f 100644 --- a/packages/app/src/i18n/br.ts +++ b/packages/app/src/i18n/br.ts @@ -627,6 +627,14 @@ export const dict = { "session.header.open.menu": "Opções de abertura", "session.header.open.copyPath": "Copiar caminho", "status.popover.trigger": "Status", + "status.popover.tools.trigger": "Ferramentas", + "status.popover.tools.mcp.description": "Adicione servidores MCP no opencode.json", + "status.popover.tools.lsp.description": "Os LSPs são detectados automaticamente ao abrir arquivos", + "status.popover.tools.plugins.description": "Adicione plugins no opencode.json", + "status.popover.tools.mcp.empty": "Nenhum MCP configurado ainda", + "status.popover.tools.lsp.empty": "Nenhum servidor de linguagem ativo ainda", + "status.popover.tools.plugins.empty": "Nenhum plugin configurado ainda", + "status.popover.tools.reauthenticate": "Autenticar novamente", "status.popover.ariaLabel": "Configurações de servidores", "status.popover.tab.servers": "Servidores", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/bs.ts b/packages/app/src/i18n/bs.ts index e0d4e2aa03..fae321a18f 100644 --- a/packages/app/src/i18n/bs.ts +++ b/packages/app/src/i18n/bs.ts @@ -685,6 +685,14 @@ export const dict = { "session.header.open.copyPath": "Kopiraj putanju", "status.popover.trigger": "Status", + "status.popover.tools.trigger": "Alati", + "status.popover.tools.mcp.description": "Dodajte MCP servere u opencode.json", + "status.popover.tools.lsp.description": "LSP serveri se automatski otkrivaju dok otvarate datoteke", + "status.popover.tools.plugins.description": "Dodajte dodatke u opencode.json", + "status.popover.tools.mcp.empty": "Još nema konfigurisanih MCP servera", + "status.popover.tools.lsp.empty": "Još nema aktivnih jezičkih servera", + "status.popover.tools.plugins.empty": "Još nema konfigurisanih dodataka", + "status.popover.tools.reauthenticate": "Ponovo se autentificiraj", "status.popover.ariaLabel": "Konfiguracije servera", "status.popover.tab.servers": "Serveri", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts index 3b02b6a026..e803009469 100644 --- a/packages/app/src/i18n/da.ts +++ b/packages/app/src/i18n/da.ts @@ -680,6 +680,14 @@ export const dict = { "session.header.open.copyPath": "Kopier sti", "status.popover.trigger": "Status", + "status.popover.tools.trigger": "Værktøjer", + "status.popover.tools.mcp.description": "Tilføj MCP-servere i opencode.json", + "status.popover.tools.lsp.description": "LSP'er registreres automatisk, når du åbner filer", + "status.popover.tools.plugins.description": "Tilføj plugins i opencode.json", + "status.popover.tools.mcp.empty": "Ingen MCP'er konfigureret endnu", + "status.popover.tools.lsp.empty": "Ingen aktive sprogservere endnu", + "status.popover.tools.plugins.empty": "Ingen plugins konfigureret endnu", + "status.popover.tools.reauthenticate": "Godkend igen", "status.popover.ariaLabel": "Serverkonfigurationer", "status.popover.tab.servers": "Servere", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts index cf530f6488..8e658cda20 100644 --- a/packages/app/src/i18n/de.ts +++ b/packages/app/src/i18n/de.ts @@ -636,6 +636,14 @@ export const dict = { "session.header.open.menu": "Öffnen-Optionen", "session.header.open.copyPath": "Pfad kopieren", "status.popover.trigger": "Status", + "status.popover.tools.trigger": "Werkzeuge", + "status.popover.tools.mcp.description": "MCP-Server in opencode.json hinzufügen", + "status.popover.tools.lsp.description": "LSPs werden beim Öffnen von Dateien automatisch erkannt", + "status.popover.tools.plugins.description": "Plugins in opencode.json hinzufügen", + "status.popover.tools.mcp.empty": "Noch keine MCPs konfiguriert", + "status.popover.tools.lsp.empty": "Noch keine aktiven Sprachserver", + "status.popover.tools.plugins.empty": "Noch keine Plugins konfiguriert", + "status.popover.tools.reauthenticate": "Erneut authentifizieren", "status.popover.ariaLabel": "Serverkonfigurationen", "status.popover.tab.servers": "Server", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index 9d122447a8..eef4dca6f9 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -728,6 +728,14 @@ export const dict = { "status.popover.trigger": "Status", "status.popover.ariaLabel": "Server configurations", + "status.popover.tools.trigger": "Tools", + "status.popover.tools.mcp.description": "Add MCP servers in opencode.json", + "status.popover.tools.lsp.description": "LSPs are auto-detected as you open files", + "status.popover.tools.plugins.description": "Add plugins in opencode.json", + "status.popover.tools.mcp.empty": "No MCPs configured yet", + "status.popover.tools.lsp.empty": "No active language servers yet", + "status.popover.tools.plugins.empty": "No plugins configured yet", + "status.popover.tools.reauthenticate": "Reauthenticate", "status.popover.tab.servers": "Servers", "status.popover.tab.mcp": "MCP", "status.popover.tab.lsp": "LSP", diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts index 0610f2de00..0dab508dbf 100644 --- a/packages/app/src/i18n/es.ts +++ b/packages/app/src/i18n/es.ts @@ -686,6 +686,14 @@ export const dict = { "session.header.open.copyPath": "Copiar ruta", "status.popover.trigger": "Estado", + "status.popover.tools.trigger": "Herramientas", + "status.popover.tools.mcp.description": "Añade servidores MCP en opencode.json", + "status.popover.tools.lsp.description": "Los LSP se detectan automáticamente al abrir archivos", + "status.popover.tools.plugins.description": "Añade plugins en opencode.json", + "status.popover.tools.mcp.empty": "Aún no hay MCP configurados", + "status.popover.tools.lsp.empty": "Aún no hay servidores de lenguaje activos", + "status.popover.tools.plugins.empty": "Aún no hay plugins configurados", + "status.popover.tools.reauthenticate": "Volver a autenticar", "status.popover.ariaLabel": "Configuraciones del servidor", "status.popover.tab.servers": "Servidores", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts index 3ed47d5dba..4627072e4a 100644 --- a/packages/app/src/i18n/fr.ts +++ b/packages/app/src/i18n/fr.ts @@ -632,6 +632,14 @@ export const dict = { "session.header.open.menu": "Options d'ouverture", "session.header.open.copyPath": "Copier le chemin", "status.popover.trigger": "Statut", + "status.popover.tools.trigger": "Outils", + "status.popover.tools.mcp.description": "Ajouter des serveurs MCP dans opencode.json", + "status.popover.tools.lsp.description": "Les LSP sont détectés automatiquement à l’ouverture des fichiers", + "status.popover.tools.plugins.description": "Ajouter des plugins dans opencode.json", + "status.popover.tools.mcp.empty": "Aucun MCP configuré pour le moment", + "status.popover.tools.lsp.empty": "Aucun serveur de langage actif pour le moment", + "status.popover.tools.plugins.empty": "Aucun plugin configuré pour le moment", + "status.popover.tools.reauthenticate": "S’authentifier à nouveau", "status.popover.ariaLabel": "Configurations des serveurs", "status.popover.tab.servers": "Serveurs", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts index 52ec83b3c4..1c91dcc688 100644 --- a/packages/app/src/i18n/ja.ts +++ b/packages/app/src/i18n/ja.ts @@ -623,6 +623,14 @@ export const dict = { "session.header.open.menu": "開くオプション", "session.header.open.copyPath": "パスをコピー", "status.popover.trigger": "ステータス", + "status.popover.tools.trigger": "ツール", + "status.popover.tools.mcp.description": "opencode.json に MCP サーバーを追加", + "status.popover.tools.lsp.description": "ファイルを開くと LSP が自動検出されます", + "status.popover.tools.plugins.description": "opencode.json にプラグインを追加", + "status.popover.tools.mcp.empty": "MCP はまだ設定されていません", + "status.popover.tools.lsp.empty": "アクティブな言語サーバーはまだありません", + "status.popover.tools.plugins.empty": "プラグインはまだ設定されていません", + "status.popover.tools.reauthenticate": "再認証", "status.popover.ariaLabel": "サーバー設定", "status.popover.tab.servers": "サーバー", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index 738123fe03..182c1d7df9 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -503,6 +503,14 @@ export const dict = { "session.header.open.menu": "열기 옵션", "session.header.open.copyPath": "경로 복사", "status.popover.trigger": "상태", + "status.popover.tools.trigger": "도구", + "status.popover.tools.mcp.description": "opencode.json에 MCP 서버 추가", + "status.popover.tools.lsp.description": "파일을 열면 LSP가 자동으로 감지됩니다", + "status.popover.tools.plugins.description": "opencode.json에 플러그인 추가", + "status.popover.tools.mcp.empty": "아직 구성된 MCP가 없습니다", + "status.popover.tools.lsp.empty": "아직 활성 언어 서버가 없습니다", + "status.popover.tools.plugins.empty": "아직 구성된 플러그인이 없습니다", + "status.popover.tools.reauthenticate": "다시 인증", "status.popover.ariaLabel": "서버 구성", "status.popover.tab.servers": "서버", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts index 0a37f8bf32..5a6b894fa7 100644 --- a/packages/app/src/i18n/no.ts +++ b/packages/app/src/i18n/no.ts @@ -567,6 +567,14 @@ export const dict = { "session.header.open.copyPath": "Kopier bane", "status.popover.trigger": "Status", + "status.popover.tools.trigger": "Verktøy", + "status.popover.tools.mcp.description": "Legg til MCP-servere i opencode.json", + "status.popover.tools.lsp.description": "LSP-er oppdages automatisk når du åpner filer", + "status.popover.tools.plugins.description": "Legg til plugins i opencode.json", + "status.popover.tools.mcp.empty": "Ingen MCP-er konfigurert ennå", + "status.popover.tools.lsp.empty": "Ingen aktive språkservere ennå", + "status.popover.tools.plugins.empty": "Ingen plugins konfigurert ennå", + "status.popover.tools.reauthenticate": "Autentiser på nytt", "status.popover.ariaLabel": "Serverkonfigurasjoner", "status.popover.tab.servers": "Servere", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts index f56e023aed..5270ffb1d7 100644 --- a/packages/app/src/i18n/pl.ts +++ b/packages/app/src/i18n/pl.ts @@ -627,6 +627,14 @@ export const dict = { "session.header.open.menu": "Opcje otwierania", "session.header.open.copyPath": "Kopiuj ścieżkę", "status.popover.trigger": "Status", + "status.popover.tools.trigger": "Narzędzia", + "status.popover.tools.mcp.description": "Dodaj serwery MCP w opencode.json", + "status.popover.tools.lsp.description": "LSP są wykrywane automatycznie podczas otwierania plików", + "status.popover.tools.plugins.description": "Dodaj wtyczki w opencode.json", + "status.popover.tools.mcp.empty": "Nie skonfigurowano jeszcze MCP", + "status.popover.tools.lsp.empty": "Brak aktywnych serwerów językowych", + "status.popover.tools.plugins.empty": "Nie skonfigurowano jeszcze wtyczek", + "status.popover.tools.reauthenticate": "Uwierzytelnij ponownie", "status.popover.ariaLabel": "Konfiguracje serwerów", "status.popover.tab.servers": "Serwery", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts index 0d68552e6d..a07e9dfdac 100644 --- a/packages/app/src/i18n/ru.ts +++ b/packages/app/src/i18n/ru.ts @@ -683,6 +683,14 @@ export const dict = { "session.header.open.copyPath": "Копировать путь", "status.popover.trigger": "Статус", + "status.popover.tools.trigger": "Инструменты", + "status.popover.tools.mcp.description": "Добавьте серверы MCP в opencode.json", + "status.popover.tools.lsp.description": "LSP определяются автоматически при открытии файлов", + "status.popover.tools.plugins.description": "Добавьте плагины в opencode.json", + "status.popover.tools.mcp.empty": "MCP пока не настроены", + "status.popover.tools.lsp.empty": "Активных языковых серверов пока нет", + "status.popover.tools.plugins.empty": "Плагины пока не настроены", + "status.popover.tools.reauthenticate": "Повторно авторизоваться", "status.popover.ariaLabel": "Настройки серверов", "status.popover.tab.servers": "Серверы", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts index 91c009be0c..3ac69230f3 100644 --- a/packages/app/src/i18n/th.ts +++ b/packages/app/src/i18n/th.ts @@ -679,6 +679,14 @@ export const dict = { "session.header.open.copyPath": "คัดลอกเส้นทาง", "status.popover.trigger": "สถานะ", + "status.popover.tools.trigger": "เครื่องมือ", + "status.popover.tools.mcp.description": "เพิ่มเซิร์ฟเวอร์ MCP ใน opencode.json", + "status.popover.tools.lsp.description": "ระบบจะตรวจพบ LSP อัตโนมัติเมื่อคุณเปิดไฟล์", + "status.popover.tools.plugins.description": "เพิ่มปลั๊กอินใน opencode.json", + "status.popover.tools.mcp.empty": "ยังไม่ได้กำหนดค่า MCP", + "status.popover.tools.lsp.empty": "ยังไม่มีเซิร์ฟเวอร์ภาษาที่ใช้งานอยู่", + "status.popover.tools.plugins.empty": "ยังไม่ได้กำหนดค่าปลั๊กอิน", + "status.popover.tools.reauthenticate": "ยืนยันตัวตนอีกครั้ง", "status.popover.ariaLabel": "การกำหนดค่าเซิร์ฟเวอร์", "status.popover.tab.servers": "เซิร์ฟเวอร์", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/tr.ts b/packages/app/src/i18n/tr.ts index ff17d0001c..7541daf543 100644 --- a/packages/app/src/i18n/tr.ts +++ b/packages/app/src/i18n/tr.ts @@ -689,6 +689,14 @@ export const dict = { "session.header.open.copyPath": "Yolu kopyala", "status.popover.trigger": "Durum", + "status.popover.tools.trigger": "Araçlar", + "status.popover.tools.mcp.description": "opencode.json dosyasına MCP sunucuları ekleyin", + "status.popover.tools.lsp.description": "Dosyaları açtığınızda LSP'ler otomatik olarak algılanır", + "status.popover.tools.plugins.description": "opencode.json dosyasına eklentiler ekleyin", + "status.popover.tools.mcp.empty": "Henüz yapılandırılmış MCP yok", + "status.popover.tools.lsp.empty": "Henüz etkin dil sunucusu yok", + "status.popover.tools.plugins.empty": "Henüz yapılandırılmış eklenti yok", + "status.popover.tools.reauthenticate": "Yeniden kimlik doğrula", "status.popover.ariaLabel": "Sunucu yapılandırmaları", "status.popover.tab.servers": "Sunucular", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/uk.ts b/packages/app/src/i18n/uk.ts index c6a0ae9629..c5dbea8beb 100644 --- a/packages/app/src/i18n/uk.ts +++ b/packages/app/src/i18n/uk.ts @@ -729,6 +729,14 @@ export const dict = { "session.header.open.app.sublimeText": "Sublime Text", "status.popover.trigger": "Статус", + "status.popover.tools.trigger": "Інструменти", + "status.popover.tools.mcp.description": "Додайте сервери MCP в opencode.json", + "status.popover.tools.lsp.description": "LSP визначаються автоматично під час відкриття файлів", + "status.popover.tools.plugins.description": "Додайте плагіни в opencode.json", + "status.popover.tools.mcp.empty": "MCP ще не налаштовано", + "status.popover.tools.lsp.empty": "Активних мовних серверів ще немає", + "status.popover.tools.plugins.empty": "Плагіни ще не налаштовано", + "status.popover.tools.reauthenticate": "Повторно автентифікуватися", "status.popover.ariaLabel": "Конфігурації серверів", "status.popover.tab.servers": "Сервери", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts index a44bfc107f..bdc81b2cb5 100644 --- a/packages/app/src/i18n/zh.ts +++ b/packages/app/src/i18n/zh.ts @@ -675,6 +675,14 @@ export const dict = { "session.header.open.copyPath": "复制路径", "status.popover.trigger": "状态", + "status.popover.tools.trigger": "工具", + "status.popover.tools.mcp.description": "在 opencode.json 中添加 MCP 服务器", + "status.popover.tools.lsp.description": "打开文件时会自动检测 LSP", + "status.popover.tools.plugins.description": "在 opencode.json 中添加插件", + "status.popover.tools.mcp.empty": "尚未配置 MCP", + "status.popover.tools.lsp.empty": "尚无活动的语言服务器", + "status.popover.tools.plugins.empty": "尚未配置插件", + "status.popover.tools.reauthenticate": "重新认证", "status.popover.ariaLabel": "服务器配置", "status.popover.tab.servers": "服务器", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts index e9a1fea29e..58e9a77563 100644 --- a/packages/app/src/i18n/zht.ts +++ b/packages/app/src/i18n/zht.ts @@ -673,6 +673,14 @@ export const dict = { "session.header.open.copyPath": "複製路徑", "status.popover.trigger": "狀態", + "status.popover.tools.trigger": "工具", + "status.popover.tools.mcp.description": "在 opencode.json 中新增 MCP 伺服器", + "status.popover.tools.lsp.description": "開啟檔案時會自動偵測 LSP", + "status.popover.tools.plugins.description": "在 opencode.json 中新增外掛程式", + "status.popover.tools.mcp.empty": "尚未設定 MCP", + "status.popover.tools.lsp.empty": "尚無作用中的語言伺服器", + "status.popover.tools.plugins.empty": "尚未設定外掛程式", + "status.popover.tools.reauthenticate": "重新驗證", "status.popover.ariaLabel": "伺服器設定", "status.popover.tab.servers": "伺服器", "status.popover.tab.mcp": "MCP", diff --git a/packages/app/src/pages/new-session.tsx b/packages/app/src/pages/new-session.tsx index 7a8e44c5ab..f557dee835 100644 --- a/packages/app/src/pages/new-session.tsx +++ b/packages/app/src/pages/new-session.tsx @@ -2,7 +2,7 @@ import { Show, createEffect, createMemo, createResource, createSignal, onCleanup import { createStore } from "solid-js/store" import { Portal } from "solid-js/web" import { useSearchParams } from "@solidjs/router" -import { Tooltip } from "@opencode-ai/ui/tooltip" +import { createMediaQuery } from "@solid-primitives/media" import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" import { NewSessionDesignView } from "@/components/session" @@ -51,6 +51,7 @@ export default function NewSessionPage() { const providers = useProviders(() => sdk().directory) const openProviderSettings = useSettingsDialog("providers") const route = useSessionKey() + const isDesktop = createMediaQuery("(min-width: 768px)") const [searchParams, setSearchParams] = useSearchParams<{ draftId?: string; prompt?: string }>() useComposerCommands() @@ -112,10 +113,10 @@ export default function NewSessionPage() { {(mount) => ( - - + + - + )} diff --git a/packages/ui/src/v2/components/icon.tsx b/packages/ui/src/v2/components/icon.tsx index b0b70bf37f..d16cc65773 100644 --- a/packages/ui/src/v2/components/icon.tsx +++ b/packages/ui/src/v2/components/icon.tsx @@ -33,6 +33,14 @@ const icons = { viewBox: "0 0 20 20", body: ``, }, + tools: { + viewBox: "0 0 16 16", + body: ``, + }, + "tools-warning": { + viewBox: "0 0 16 16", + body: ``, + }, "status-active": { viewBox: "0 0 20 20", body: ``,