feat(antigravity): implement Antigravity OAuth integration with UI elements and functionality

This commit is contained in:
Supra4E8C
2025-11-23 17:56:17 +08:00
parent 6962667171
commit 970297f3ae
5 changed files with 209 additions and 0 deletions

16
app.js
View File

@@ -221,6 +221,7 @@ class CLIProxyManager {
const cardText = card.textContent || ''; const cardText = card.textContent || '';
if (cardText.includes('Codex OAuth') || if (cardText.includes('Codex OAuth') ||
cardText.includes('Anthropic OAuth') || cardText.includes('Anthropic OAuth') ||
cardText.includes('Antigravity OAuth') ||
cardText.includes('Gemini CLI OAuth') || cardText.includes('Gemini CLI OAuth') ||
cardText.includes('Qwen OAuth') || cardText.includes('Qwen OAuth') ||
cardText.includes('iFlow OAuth')) { cardText.includes('iFlow OAuth')) {
@@ -430,6 +431,21 @@ class CLIProxyManager {
anthropicCopyLink.addEventListener('click', () => this.copyAnthropicLink()); anthropicCopyLink.addEventListener('click', () => this.copyAnthropicLink());
} }
// Antigravity OAuth
const antigravityOauthBtn = document.getElementById('antigravity-oauth-btn');
const antigravityOpenLink = document.getElementById('antigravity-open-link');
const antigravityCopyLink = document.getElementById('antigravity-copy-link');
if (antigravityOauthBtn) {
antigravityOauthBtn.addEventListener('click', () => this.startAntigravityOAuth());
}
if (antigravityOpenLink) {
antigravityOpenLink.addEventListener('click', () => this.openAntigravityLink());
}
if (antigravityCopyLink) {
antigravityCopyLink.addEventListener('click', () => this.copyAntigravityLink());
}
// Gemini CLI OAuth // Gemini CLI OAuth
const geminiCliOauthBtn = document.getElementById('gemini-cli-oauth-btn'); const geminiCliOauthBtn = document.getElementById('gemini-cli-oauth-btn');
const geminiCliOpenLink = document.getElementById('gemini-cli-open-link'); const geminiCliOpenLink = document.getElementById('gemini-cli-open-link');

26
i18n.js
View File

@@ -333,6 +333,19 @@ const i18n = {
'auth_login.anthropic_oauth_start_error': '启动 Anthropic OAuth 失败:', 'auth_login.anthropic_oauth_start_error': '启动 Anthropic OAuth 失败:',
'auth_login.anthropic_oauth_polling_error': '检查认证状态失败:', 'auth_login.anthropic_oauth_polling_error': '检查认证状态失败:',
// Antigravity OAuth
'auth_login.antigravity_oauth_title': 'Antigravity OAuth',
'auth_login.antigravity_oauth_button': '开始 Antigravity 登录',
'auth_login.antigravity_oauth_hint': '通过 OAuth 流程登录 AntigravityGoogle 账号)服务,自动获取并保存认证文件。',
'auth_login.antigravity_oauth_url_label': '授权链接:',
'auth_login.antigravity_open_link': '打开链接',
'auth_login.antigravity_copy_link': '复制链接',
'auth_login.antigravity_oauth_status_waiting': '等待认证中...',
'auth_login.antigravity_oauth_status_success': '认证成功!',
'auth_login.antigravity_oauth_status_error': '认证失败:',
'auth_login.antigravity_oauth_start_error': '启动 Antigravity OAuth 失败:',
'auth_login.antigravity_oauth_polling_error': '检查认证状态失败:',
// Gemini CLI OAuth // Gemini CLI OAuth
'auth_login.gemini_cli_oauth_title': 'Gemini CLI OAuth', 'auth_login.gemini_cli_oauth_title': 'Gemini CLI OAuth',
'auth_login.gemini_cli_oauth_button': '开始 Gemini CLI 登录', 'auth_login.gemini_cli_oauth_button': '开始 Gemini CLI 登录',
@@ -854,6 +867,19 @@ const i18n = {
'auth_login.anthropic_oauth_start_error': 'Failed to start Anthropic OAuth:', 'auth_login.anthropic_oauth_start_error': 'Failed to start Anthropic OAuth:',
'auth_login.anthropic_oauth_polling_error': 'Failed to check authentication status:', 'auth_login.anthropic_oauth_polling_error': 'Failed to check authentication status:',
// Antigravity OAuth
'auth_login.antigravity_oauth_title': 'Antigravity OAuth',
'auth_login.antigravity_oauth_button': 'Start Antigravity Login',
'auth_login.antigravity_oauth_hint': 'Login to Antigravity service (Google account) through OAuth flow, automatically obtain and save authentication files.',
'auth_login.antigravity_oauth_url_label': 'Authorization URL:',
'auth_login.antigravity_open_link': 'Open Link',
'auth_login.antigravity_copy_link': 'Copy Link',
'auth_login.antigravity_oauth_status_waiting': 'Waiting for authentication...',
'auth_login.antigravity_oauth_status_success': 'Authentication successful!',
'auth_login.antigravity_oauth_status_error': 'Authentication failed:',
'auth_login.antigravity_oauth_start_error': 'Failed to start Antigravity OAuth:',
'auth_login.antigravity_oauth_polling_error': 'Failed to check authentication status:',
// Gemini CLI OAuth // Gemini CLI OAuth
'auth_login.gemini_cli_oauth_title': 'Gemini CLI OAuth', 'auth_login.gemini_cli_oauth_title': 'Gemini CLI OAuth',
'auth_login.gemini_cli_oauth_button': 'Start Gemini CLI Login', 'auth_login.gemini_cli_oauth_button': 'Start Gemini CLI Login',

View File

@@ -628,6 +628,42 @@
</div> </div>
</div> </div>
<!-- Antigravity OAuth -->
<div class="card" id="antigravity-oauth-card">
<div class="card-header">
<h3><i class="fas fa-rocket"></i> <span
data-i18n="auth_login.antigravity_oauth_title">Antigravity OAuth</span></h3>
<button id="antigravity-oauth-btn" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i> <span
data-i18n="auth_login.antigravity_oauth_button">开始 Antigravity 登录</span>
</button>
</div>
<div class="card-content">
<p class="form-hint" style="margin-bottom: 20px;"
data-i18n="auth_login.antigravity_oauth_hint">
通过 OAuth 流程登录 AntigravityGoogle 账号)服务,自动获取并保存认证文件。
</p>
<div id="antigravity-oauth-content" style="display: none;">
<div class="form-group">
<label data-i18n="auth_login.antigravity_oauth_url_label">授权链接:</label>
<div class="input-group">
<input type="text" id="antigravity-oauth-url" readonly>
<button id="antigravity-open-link" class="btn btn-primary">
<i class="fas fa-external-link-alt"></i> <span
data-i18n="auth_login.antigravity_open_link">打开链接</span>
</button>
<button id="antigravity-copy-link" class="btn btn-secondary">
<i class="fas fa-copy"></i> <span
data-i18n="auth_login.antigravity_copy_link">复制链接</span>
</button>
</div>
</div>
<div id="antigravity-oauth-status" class="form-hint" style="margin-top: 10px;">
</div>
</div>
</div>
</div>
<!-- Gemini CLI OAuth --> <!-- Gemini CLI OAuth -->
<div class="card" id="gemini-cli-oauth-card"> <div class="card" id="gemini-cli-oauth-card">
<div class="card-header"> <div class="card-header">

View File

@@ -300,6 +300,135 @@ export const oauthModule = {
} }
}, },
// ===== Antigravity OAuth 相关方法 =====
// 开始 Antigravity OAuth 流程
async startAntigravityOAuth() {
try {
const response = await this.makeRequest('/antigravity-auth-url?is_webui=1');
const authUrl = response.url;
const state = response.state || this.extractStateFromUrl(authUrl);
// 显示授权链接
const urlInput = document.getElementById('antigravity-oauth-url');
const content = document.getElementById('antigravity-oauth-content');
const status = document.getElementById('antigravity-oauth-status');
if (urlInput) {
urlInput.value = authUrl;
}
if (content) {
content.style.display = 'block';
}
if (status) {
status.textContent = i18n.t('auth_login.antigravity_oauth_status_waiting');
status.style.color = 'var(--warning-text)';
}
// 开始轮询认证状态
this.startAntigravityOAuthPolling(state);
} catch (error) {
this.showNotification(`${i18n.t('auth_login.antigravity_oauth_start_error')} ${error.message}`, 'error');
}
},
// 打开 Antigravity 授权链接
openAntigravityLink() {
const urlInput = document.getElementById('antigravity-oauth-url');
if (urlInput && urlInput.value) {
window.open(urlInput.value, '_blank');
}
},
// 复制 Antigravity 授权链接
async copyAntigravityLink() {
const urlInput = document.getElementById('antigravity-oauth-url');
if (urlInput && urlInput.value) {
try {
await navigator.clipboard.writeText(urlInput.value);
this.showNotification(i18n.t('notification.link_copied'), 'success');
} catch (error) {
urlInput.select();
document.execCommand('copy');
this.showNotification(i18n.t('notification.link_copied'), 'success');
}
}
},
// 开始轮询 Antigravity OAuth 状态
startAntigravityOAuthPolling(state) {
if (!state) {
this.showNotification(i18n.t('auth_login.missing_state'), 'error');
return;
}
const pollInterval = setInterval(async () => {
try {
const response = await this.makeRequest(`/get-auth-status?state=${encodeURIComponent(state)}`);
const status = response.status;
const statusElement = document.getElementById('antigravity-oauth-status');
if (status === 'ok') {
clearInterval(pollInterval);
this.resetAntigravityOAuthUI();
this.showNotification(i18n.t('auth_login.antigravity_oauth_status_success'), 'success');
this.loadAuthFiles();
} else if (status === 'error') {
clearInterval(pollInterval);
const errorMessage = response.error || 'Unknown error';
if (statusElement) {
statusElement.textContent = `${i18n.t('auth_login.antigravity_oauth_status_error')} ${errorMessage}`;
statusElement.style.color = 'var(--error-text)';
}
this.showNotification(`${i18n.t('auth_login.antigravity_oauth_status_error')} ${errorMessage}`, 'error');
setTimeout(() => {
this.resetAntigravityOAuthUI();
}, 3000);
} else if (status === 'wait') {
if (statusElement) {
statusElement.textContent = i18n.t('auth_login.antigravity_oauth_status_waiting');
statusElement.style.color = 'var(--warning-text)';
}
}
} catch (error) {
clearInterval(pollInterval);
const statusElement = document.getElementById('antigravity-oauth-status');
if (statusElement) {
statusElement.textContent = `${i18n.t('auth_login.antigravity_oauth_polling_error')} ${error.message}`;
statusElement.style.color = 'var(--error-text)';
}
this.showNotification(`${i18n.t('auth_login.antigravity_oauth_polling_error')} ${error.message}`, 'error');
setTimeout(() => {
this.resetAntigravityOAuthUI();
}, 3000);
}
}, 2000);
setTimeout(() => {
clearInterval(pollInterval);
}, 5 * 60 * 1000);
},
// 重置 Antigravity OAuth UI 到初始状态
resetAntigravityOAuthUI() {
const urlInput = document.getElementById('antigravity-oauth-url');
const content = document.getElementById('antigravity-oauth-content');
const status = document.getElementById('antigravity-oauth-status');
if (urlInput) {
urlInput.value = '';
}
if (content) {
content.style.display = 'none';
}
if (status) {
status.textContent = '';
status.style.color = '';
status.className = '';
}
},
// ===== Gemini CLI OAuth 相关方法 ===== // ===== Gemini CLI OAuth 相关方法 =====
// 开始 Gemini CLI OAuth 流程 // 开始 Gemini CLI OAuth 流程

View File

@@ -109,6 +109,7 @@ export const REQUEST_TIMEOUT_MS = 30 * 1000;
export const OAUTH_CARD_IDS = [ export const OAUTH_CARD_IDS = [
'codex-oauth-card', 'codex-oauth-card',
'anthropic-oauth-card', 'anthropic-oauth-card',
'antigravity-oauth-card',
'gemini-cli-oauth-card', 'gemini-cli-oauth-card',
'qwen-oauth-card', 'qwen-oauth-card',
'iflow-oauth-card' 'iflow-oauth-card'
@@ -120,6 +121,7 @@ export const OAUTH_CARD_IDS = [
export const OAUTH_PROVIDERS = { export const OAUTH_PROVIDERS = {
CODEX: 'codex', CODEX: 'codex',
ANTHROPIC: 'anthropic', ANTHROPIC: 'anthropic',
ANTIGRAVITY: 'antigravity',
GEMINI_CLI: 'gemini-cli', GEMINI_CLI: 'gemini-cli',
QWEN: 'qwen', QWEN: 'qwen',
IFLOW: 'iflow' IFLOW: 'iflow'