mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-02 18:39:06 +08:00
fix(mcp): resolve OAuth callback page hanging and add i18n support (#11195)
- Fix OAuth callback server not sending HTTP response, causing browser to hang - Add internationalization support for OAuth callback page (10 languages) - Simplify callback page design with clean white background - Improve user experience with localized success messages Changes: - src/main/services/mcp/oauth/callback.ts: Add HTTP response to OAuth callback - src/renderer/src/i18n/: Add callback page translations for all supported languages Signed-off-by: charles <kidccc@gmail.com>
This commit is contained in:
parent
57d9a31c0f
commit
ed453750fe
@ -1,4 +1,6 @@
|
||||
import { loggerService } from '@logger'
|
||||
import { configManager } from '@main/services/ConfigManager'
|
||||
import { locales } from '@main/utils/locales'
|
||||
import type EventEmitter from 'events'
|
||||
import http from 'http'
|
||||
import { URL } from 'url'
|
||||
@ -7,6 +9,36 @@ import type { OAuthCallbackServerOptions } from './types'
|
||||
|
||||
const logger = loggerService.withContext('MCP:OAuthCallbackServer')
|
||||
|
||||
function getTranslation(key: string): string {
|
||||
const language = configManager.getLanguage()
|
||||
const localeData = locales[language]
|
||||
|
||||
if (!localeData) {
|
||||
logger.warn(`No locale data found for language: ${language}`)
|
||||
return key
|
||||
}
|
||||
|
||||
const translations = localeData.translation as any
|
||||
if (!translations) {
|
||||
logger.warn(`No translations found for language: ${language}`)
|
||||
return key
|
||||
}
|
||||
|
||||
const keys = key.split('.')
|
||||
let value = translations
|
||||
|
||||
for (const k of keys) {
|
||||
if (value && typeof value === 'object' && k in value) {
|
||||
value = value[k]
|
||||
} else {
|
||||
logger.warn(`Translation key not found: ${key} (failed at: ${k})`)
|
||||
return key // fallback to key if translation not found
|
||||
}
|
||||
}
|
||||
|
||||
return typeof value === 'string' ? value : key
|
||||
}
|
||||
|
||||
export class CallBackServer {
|
||||
private server: Promise<http.Server>
|
||||
private events: EventEmitter
|
||||
@ -28,6 +60,55 @@ export class CallBackServer {
|
||||
if (code) {
|
||||
// Emit the code event
|
||||
this.events.emit('auth-code-received', code)
|
||||
// Send success response to browser
|
||||
const title = getTranslation('settings.mcp.oauth.callback.title')
|
||||
const message = getTranslation('settings.mcp.oauth.callback.message')
|
||||
|
||||
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
|
||||
res.end(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>${title}</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
background: #ffffff;
|
||||
}
|
||||
.container {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
h1 {
|
||||
color: #2d3748;
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
p {
|
||||
color: #718096;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>${title}</h1>
|
||||
<p>${message}</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
} else {
|
||||
res.writeHead(400, { 'Content-Type': 'text/plain' })
|
||||
res.end('Missing authorization code')
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error processing OAuth callback:', error as Error)
|
||||
|
||||
@ -3863,6 +3863,12 @@
|
||||
"usage": "Usage",
|
||||
"version": "Version"
|
||||
},
|
||||
"oauth": {
|
||||
"callback": {
|
||||
"message": "You can close this page and return to Cherry Studio",
|
||||
"title": "Authentication Successful"
|
||||
}
|
||||
},
|
||||
"prompts": {
|
||||
"arguments": "Arguments",
|
||||
"availablePrompts": "Available Prompts",
|
||||
|
||||
@ -3863,6 +3863,12 @@
|
||||
"usage": "用法",
|
||||
"version": "版本"
|
||||
},
|
||||
"oauth": {
|
||||
"callback": {
|
||||
"message": "您可以关闭此页面并返回 Cherry Studio",
|
||||
"title": "认证成功"
|
||||
}
|
||||
},
|
||||
"prompts": {
|
||||
"arguments": "参数",
|
||||
"availablePrompts": "可用提示",
|
||||
|
||||
@ -3863,6 +3863,12 @@
|
||||
"usage": "用法",
|
||||
"version": "版本"
|
||||
},
|
||||
"oauth": {
|
||||
"callback": {
|
||||
"message": "您可以關閉此頁面並返回 Cherry Studio",
|
||||
"title": "認證成功"
|
||||
}
|
||||
},
|
||||
"prompts": {
|
||||
"arguments": "參數",
|
||||
"availablePrompts": "可用提示",
|
||||
|
||||
@ -3863,6 +3863,12 @@
|
||||
"usage": "Verwendung",
|
||||
"version": "Version"
|
||||
},
|
||||
"oauth": {
|
||||
"callback": {
|
||||
"message": "Sie können diese Seite schließen und zu Cherry Studio zurückkehren",
|
||||
"title": "Authentifizierung erfolgreich"
|
||||
}
|
||||
},
|
||||
"prompts": {
|
||||
"arguments": "Parameter",
|
||||
"availablePrompts": "Verfügbare Prompts",
|
||||
|
||||
@ -3863,6 +3863,12 @@
|
||||
"usage": "Χρήση",
|
||||
"version": "Έκδοση"
|
||||
},
|
||||
"oauth": {
|
||||
"callback": {
|
||||
"message": "Μπορείτε να κλείσετε αυτήν τη σελίδα και να επιστρέψετε στο Cherry Studio",
|
||||
"title": "Επιτυχής Ταυτοποίηση"
|
||||
}
|
||||
},
|
||||
"prompts": {
|
||||
"arguments": "Ορίσματα",
|
||||
"availablePrompts": "Διαθέσιμες Υποδείξεις",
|
||||
|
||||
@ -3863,6 +3863,12 @@
|
||||
"usage": "Uso",
|
||||
"version": "Versión"
|
||||
},
|
||||
"oauth": {
|
||||
"callback": {
|
||||
"message": "Puede cerrar esta página y volver a Cherry Studio",
|
||||
"title": "Autenticación Exitosa"
|
||||
}
|
||||
},
|
||||
"prompts": {
|
||||
"arguments": "Argumentos",
|
||||
"availablePrompts": "Indicaciones disponibles",
|
||||
|
||||
@ -3863,6 +3863,12 @@
|
||||
"usage": "Utilisation",
|
||||
"version": "Version"
|
||||
},
|
||||
"oauth": {
|
||||
"callback": {
|
||||
"message": "Vous pouvez fermer cette page et retourner à Cherry Studio",
|
||||
"title": "Authentification Réussie"
|
||||
}
|
||||
},
|
||||
"prompts": {
|
||||
"arguments": "Arguments",
|
||||
"availablePrompts": "Invites disponibles",
|
||||
|
||||
@ -3863,6 +3863,12 @@
|
||||
"usage": "使用法",
|
||||
"version": "バージョン"
|
||||
},
|
||||
"oauth": {
|
||||
"callback": {
|
||||
"message": "このページを閉じてCherry Studioに戻ることができます",
|
||||
"title": "認証成功"
|
||||
}
|
||||
},
|
||||
"prompts": {
|
||||
"arguments": "引数",
|
||||
"availablePrompts": "利用可能なプロンプト",
|
||||
|
||||
@ -3863,6 +3863,12 @@
|
||||
"usage": "Uso",
|
||||
"version": "Versão"
|
||||
},
|
||||
"oauth": {
|
||||
"callback": {
|
||||
"message": "Você pode fechar esta página e retornar ao Cherry Studio",
|
||||
"title": "Autenticação Bem-Sucedida"
|
||||
}
|
||||
},
|
||||
"prompts": {
|
||||
"arguments": "Argumentos",
|
||||
"availablePrompts": "Dicas disponíveis",
|
||||
|
||||
@ -3863,6 +3863,12 @@
|
||||
"usage": "Использование",
|
||||
"version": "Версия"
|
||||
},
|
||||
"oauth": {
|
||||
"callback": {
|
||||
"message": "Вы можете закрыть эту страницу и вернуться в Cherry Studio",
|
||||
"title": "Аутентификация Успешна"
|
||||
}
|
||||
},
|
||||
"prompts": {
|
||||
"arguments": "Аргументы",
|
||||
"availablePrompts": "Доступные подсказки",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user