fix(misc): MCP settings and other UI improvements/fixes (#10141)

This commit is contained in:
llamantino 2025-08-13 16:30:38 +02:00 committed by GitHub
parent e3411f743d
commit 69fa580899
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 50 additions and 42 deletions

View File

@ -1,8 +1,10 @@
import { Lock } from "lucide-react";
import { useTranslation } from "react-i18next";
import { ContextMenu } from "./context-menu";
import { ContextMenuListItem } from "./context-menu-list-item";
import { useClickOutsideElement } from "#/hooks/use-click-outside-element";
import { I18nKey } from "#/i18n/declaration";
import { ContextMenuIconText } from "./context-menu-icon-text";
interface AccountSettingsContextMenuProps {
onLogout: () => void;
@ -23,7 +25,10 @@ export function AccountSettingsContextMenu({
className="absolute right-full md:left-full -top-1 z-10 w-fit"
>
<ContextMenuListItem onClick={onLogout} data-testid="logout-button">
{t(I18nKey.ACCOUNT_SETTINGS$LOGOUT)}
<ContextMenuIconText
icon={Lock}
text={t(I18nKey.ACCOUNT_SETTINGS$LOGOUT)}
/>
</ContextMenuListItem>
</ContextMenu>
);

View File

@ -13,6 +13,7 @@ export function ConnectToProviderMessage() {
<Link
data-testid="navigate-to-settings-button"
to="/settings/integrations"
className="self-start"
>
<BrandButton type="button" variant="primary" isDisabled={isLoading}>
{!isLoading && t("SETTINGS$TITLE")}

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useState, useRef, useEffect } from "react";
import { useTranslation, Trans } from "react-i18next";
import { MCPConfig } from "#/types/settings";
import { I18nKey } from "#/i18n/declaration";
@ -11,6 +11,11 @@ interface MCPJsonEditorProps {
onCancel: () => void;
}
const MCP_DEFAULT_CONFIG: MCPConfig = {
sse_servers: [],
stdio_servers: [],
};
export function MCPJsonEditor({
mcpConfig,
onChange,
@ -20,10 +25,17 @@ export function MCPJsonEditor({
const [configText, setConfigText] = useState(() =>
mcpConfig
? JSON.stringify(mcpConfig, null, 2)
: t(I18nKey.SETTINGS$MCP_DEFAULT_CONFIG),
: JSON.stringify(MCP_DEFAULT_CONFIG, null, 2),
);
const [error, setError] = useState<string | null>(null);
const textareaRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
textareaRef.current?.focus();
}, []);
const handleTextChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setConfigText(e.target.value);
};
@ -89,6 +101,7 @@ export function MCPJsonEditor({
/>
</p>
<textarea
ref={textareaRef}
className={cn(
"w-full h-64 resize-y p-2 rounded-sm text-sm font-mono",
"bg-tertiary border border-[#717888]",
@ -118,7 +131,7 @@ export function MCPJsonEditor({
{t(I18nKey.BUTTON$CANCEL)}
</BrandButton>
<BrandButton type="button" variant="primary" onClick={handleSave}>
{t(I18nKey.SETTINGS$MCP_CONFIRM_CHANGES)}
{t(I18nKey.SETTINGS$MCP_PREVIEW_CHANGES)}
</BrandButton>
</div>
</div>

View File

@ -51,7 +51,7 @@ export enum I18nKey {
SETTINGS$NAV_MCP = "SETTINGS$NAV_MCP",
SETTINGS$MCP_CONFIGURATION = "SETTINGS$MCP_CONFIGURATION",
SETTINGS$MCP_EDIT_CONFIGURATION = "SETTINGS$MCP_EDIT_CONFIGURATION",
SETTINGS$MCP_CONFIRM_CHANGES = "SETTINGS$MCP_CONFIRM_CHANGES",
SETTINGS$MCP_PREVIEW_CHANGES = "SETTINGS$MCP_PREVIEW_CHANGES",
SETTINGS$MCP_CONFIG_DESCRIPTION = "SETTINGS$MCP_CONFIG_DESCRIPTION",
SETTINGS$MCP_CONFIG_ERROR = "SETTINGS$MCP_CONFIG_ERROR",
SETTINGS$MCP_CONFIG_EXAMPLE = "SETTINGS$MCP_CONFIG_EXAMPLE",
@ -71,7 +71,6 @@ export enum I18nKey {
SETTINGS$MCP_ERROR_SSE_URL = "SETTINGS$MCP_ERROR_SSE_URL",
SETTINGS$MCP_ERROR_STDIO_PROPS = "SETTINGS$MCP_ERROR_STDIO_PROPS",
SETTINGS$MCP_ERROR_INVALID_JSON = "SETTINGS$MCP_ERROR_INVALID_JSON",
SETTINGS$MCP_DEFAULT_CONFIG = "SETTINGS$MCP_DEFAULT_CONFIG",
HOME$CONNECT_PROVIDER_MESSAGE = "HOME$CONNECT_PROVIDER_MESSAGE",
HOME$LETS_START_BUILDING = "HOME$LETS_START_BUILDING",
HOME$OPENHANDS_DESCRIPTION = "HOME$OPENHANDS_DESCRIPTION",

View File

@ -815,21 +815,21 @@
"de": "Konfiguration bearbeiten",
"uk": "Редагувати налаштування"
},
"SETTINGS$MCP_CONFIRM_CHANGES": {
"en": "Confirm Changes",
"ja": "変更を確定",
"zh-CN": "确认更改",
"zh-TW": "確認變更",
"ko-KR": "변경 사항 확인",
"no": "Bekreft endringer",
"it": "Conferma modifiche",
"pt": "Confirmar alterações",
"es": "Confirmar cambios",
"ar": "تأكيد التغييرات",
"fr": "Confirmer les modifications",
"tr": "Değişiklikleri Onayla",
"de": "Änderungen bestätigen",
"uk": ідтвердити зміни"
"SETTINGS$MCP_PREVIEW_CHANGES": {
"en": "Preview Changes",
"ja": "変更内容をプレビュー",
"zh-CN": "预览更改",
"zh-TW": "預覽變更",
"ko-KR": "변경 사항 미리보기",
"no": "Forhåndsvis endringer",
"it": "Anteprima modifiche",
"pt": "Visualizar alterações",
"es": "Vista previa de los cambios",
"ar": "معاينة التغييرات",
"fr": "Aperçu des modifications",
"tr": "Değişiklikleri Önizle",
"de": "Änderungen anzeigen",
"uk": ереглянути зміни"
},
"SETTINGS$MCP_CONFIG_DESCRIPTION": {
"en": "Edit the JSON configuration for MCP servers below. The configuration must include both sse_servers and stdio_servers arrays. For full configuration details and integration examples, see the <a>documentation</a>.",
@ -1135,22 +1135,6 @@
"de": "Ungültiges JSON",
"uk": "Невірний JSON"
},
"SETTINGS$MCP_DEFAULT_CONFIG": {
"en": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"ja": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"zh-CN": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"zh-TW": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"ko-KR": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"no": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"it": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"pt": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"es": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"ar": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"fr": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"tr": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"de": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}",
"uk": "{\n \"sse_servers\": [],\n \"stdio_servers\": []\n}"
},
"HOME$CONNECT_PROVIDER_MESSAGE": {
"en": "To get started with suggested tasks, please connect your GitHub, GitLab, or Bitbucket account.",
"ja": "提案されたタスクを始めるには、GitHub、GitLab、またはBitbucketアカウントを接続してください。",

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import posthog from "posthog-js";
import { useSettings } from "#/hooks/query/use-settings";
@ -18,11 +18,15 @@ function MCPSettingsScreen() {
const { data: settings, isLoading } = useSettings();
const { mutate: saveSettings, isPending } = useSaveSettings();
const [mcpConfig, setMcpConfig] = useState<MCPConfig | undefined>(
settings?.MCP_CONFIG,
);
const [mcpConfig, setMcpConfig] = useState<MCPConfig | undefined>(undefined);
const [isDirty, setIsDirty] = useState(false);
useEffect(() => {
if (!mcpConfig && settings?.MCP_CONFIG) {
setMcpConfig(settings.MCP_CONFIG);
}
}, [settings, mcpConfig]);
const handleConfigChange = (config: MCPConfig) => {
setMcpConfig(config);
setIsDirty(true);

View File

@ -89,6 +89,7 @@ function SecretsSettingsScreen() {
to="/settings/integrations"
data-testid="connect-git-button"
type="button"
className="self-start"
>
<BrandButton type="button" variant="secondary">
{t(I18nKey.SECRETS$CONNECT_GIT_PROVIDER)}

View File

@ -47,7 +47,8 @@ export function getIndicatorColor(
webSocketStatus === "DISCONNECTED" ||
conversationStatus === "STOPPED" ||
runtimeStatus === "STATUS$STOPPED" ||
agentState === AgentState.STOPPED
agentState === AgentState.STOPPED ||
agentState === AgentState.ERROR
) {
return IndicatorColor.RED;
}