Compare commits

...

13 Commits

Author SHA1 Message Date
Supra4E8C
3468fd8373 feat(app.js, styles): enhance connection state handling and update editor dimensions
- Added a new property to track the last connection state in CLIProxyManager.
- Updated the config editor availability logic to reflect changes in connection state.
- Increased minimum height for various editor components in styles to improve usability.
- Introduced responsive styles for smaller screens to ensure proper display of editor elements.
2025-11-10 18:07:31 +08:00
Supra4E8C
4f15c3f5c5 feat(app.js, i18n): enforce required base URL for Codex API configuration
- Updated the Codex API configuration modals to mark the Base URL field as required.
- Added validation to ensure the Base URL is provided before submission, with appropriate error notifications.
- Updated internationalization strings to reflect the change in the Base URL label from "Optional" to "Required" in both English and Chinese.
2025-11-10 12:16:46 +08:00
hkfires
72cd117aab fix(logs): exclude all /v0/management/ API entries from viewer 2025-11-10 10:40:28 +08:00
hkfires
5d62cd91f2 perf(cli): prefetch /usage, derive keyStats, reuse across renders 2025-11-10 10:32:57 +08:00
Supra4E8C
6837100dec feat(app.js, i18n, styles): implement custom headers functionality in API key management
- Added the ability to input custom HTTP headers for API keys in the CLIProxyManager.
- Introduced new methods for adding, populating, collecting, and applying custom headers.
- Updated the UI to include input fields for custom headers in the modals for adding and editing API keys.
- Enhanced internationalization strings to support custom headers in both English and Chinese.
- Added corresponding styles for the new header input fields and badges in the UI.
2025-11-09 18:27:29 +08:00
Supra4E8C
8542041981 feat(app.js, i18n): support batch addition of Gemini API keys with enhanced UI
- Updated the Gemini API key modal to allow input of multiple keys, each on a new line.
- Added a hint for users on how to input multiple keys and updated the corresponding internationalization strings.
- Enhanced the key addition logic to handle success, skipped, and failed counts, providing detailed feedback to users.
- Improved error handling and notifications for batch operations.
2025-11-09 18:06:56 +08:00
Supra4E8C
35ceab0dae feat(app.js, i18n): enhance Gemini API key management with base URL support
- Updated the CLIProxyManager to handle both API keys and optional base URLs for Gemini.
- Added new input fields in the modal for base URL entry during key addition and editing.
- Updated internationalization strings to include labels and placeholders for the base URL in both English and Chinese.
- Improved key normalization and rendering logic to accommodate the new structure.
2025-11-09 17:51:38 +08:00
Supra4E8C
d3fe186df7 refactor(app.js): remove modal click event listener to streamline modal behavior 2025-11-09 17:20:02 +08:00
Supra4E8C
5aff22a20b fix(ui): update modal styles for better responsiveness and overflow handling 2025-11-09 17:17:49 +08:00
hkfires
aa1dedc932 feat(ui): mark runtime-only auth files and disable actions 2025-11-07 22:02:29 +08:00
hkfires
61e75eee97 feat(auth-files): add AI Studio and Gemini CLI with filename masking 2025-11-07 21:46:46 +08:00
hkfires
3a2d96725f fix(ui): align file-item footer and adjust badge spacing 2025-11-06 14:23:07 +08:00
Supra4E8C
8283e99909 fix(app.js):尝试修复codex配置异常丢失数据的问题 2025-11-05 18:06:22 +08:00
5 changed files with 672 additions and 120 deletions

609
app.js

File diff suppressed because it is too large Load Diff

50
i18n.js
View File

@@ -41,6 +41,11 @@ const i18n = {
'common.failure': '失败',
'common.unknown_error': '未知错误',
'common.copy': '复制',
'common.custom_headers_label': '自定义请求头',
'common.custom_headers_hint': '可选,设置需要附带到请求中的 HTTP 头,名称和值均不能为空。',
'common.custom_headers_add': '添加请求头',
'common.custom_headers_key_placeholder': 'Header 名称,例如 X-Custom-Header',
'common.custom_headers_value_placeholder': 'Header 值',
// 页面标题
'title.main': 'CLI Proxy API Management Center',
@@ -131,10 +136,14 @@ const i18n = {
'ai_providers.gemini_empty_desc': '点击上方按钮添加第一个密钥',
'ai_providers.gemini_item_title': 'Gemini密钥',
'ai_providers.gemini_add_modal_title': '添加Gemini API密钥',
'ai_providers.gemini_add_modal_key_label': 'API密钥:',
'ai_providers.gemini_add_modal_key_placeholder': '请输入Gemini API密钥',
'ai_providers.gemini_add_modal_key_label': 'API密钥列表:',
'ai_providers.gemini_add_modal_key_placeholder': '请输入Gemini API密钥(每行一个)',
'ai_providers.gemini_add_modal_key_hint': '可一次粘贴多个密钥,每行一个。',
'ai_providers.gemini_add_modal_url_label': 'Base URL (可选):',
'ai_providers.gemini_add_modal_url_placeholder': '例如: https://generativelanguage.googleapis.com',
'ai_providers.gemini_edit_modal_title': '编辑Gemini API密钥',
'ai_providers.gemini_edit_modal_key_label': 'API密钥:',
'ai_providers.gemini_edit_modal_url_label': 'Base URL (可选):',
'ai_providers.gemini_delete_confirm': '确定要删除这个Gemini密钥吗',
'ai_providers.codex_title': 'Codex API 配置',
@@ -145,13 +154,13 @@ const i18n = {
'ai_providers.codex_add_modal_title': '添加Codex API配置',
'ai_providers.codex_add_modal_key_label': 'API密钥:',
'ai_providers.codex_add_modal_key_placeholder': '请输入Codex API密钥',
'ai_providers.codex_add_modal_url_label': 'Base URL (可选):',
'ai_providers.codex_add_modal_url_label': 'Base URL (必填):',
'ai_providers.codex_add_modal_url_placeholder': '例如: https://api.example.com',
'ai_providers.codex_add_modal_proxy_label': '代理 URL (可选):',
'ai_providers.codex_add_modal_proxy_placeholder': '例如: socks5://proxy.example.com:1080',
'ai_providers.codex_edit_modal_title': '编辑Codex API配置',
'ai_providers.codex_edit_modal_key_label': 'API密钥:',
'ai_providers.codex_edit_modal_url_label': 'Base URL (可选):',
'ai_providers.codex_edit_modal_url_label': 'Base URL (必填):',
'ai_providers.codex_edit_modal_proxy_label': '代理 URL (可选):',
'ai_providers.codex_delete_confirm': '确定要删除这个Codex配置吗',
@@ -225,6 +234,8 @@ const i18n = {
'auth_files.filter_all': '全部',
'auth_files.filter_qwen': 'Qwen',
'auth_files.filter_gemini': 'Gemini',
'auth_files.filter_gemini-cli': 'GeminiCLI',
'auth_files.filter_aistudio': 'AIStudio',
'auth_files.filter_claude': 'Claude',
'auth_files.filter_codex': 'Codex',
'auth_files.filter_iflow': 'iFlow',
@@ -232,6 +243,8 @@ const i18n = {
'auth_files.filter_unknown': '其他',
'auth_files.type_qwen': 'Qwen',
'auth_files.type_gemini': 'Gemini',
'auth_files.type_gemini-cli': 'GeminiCLI',
'auth_files.type_aistudio': 'AIStudio',
'auth_files.type_claude': 'Claude',
'auth_files.type_codex': 'Codex',
'auth_files.type_iflow': 'iFlow',
@@ -396,9 +409,13 @@ const i18n = {
'notification.gemini_key_added': 'Gemini密钥添加成功',
'notification.gemini_key_updated': 'Gemini密钥更新成功',
'notification.gemini_key_deleted': 'Gemini密钥删除成功',
'notification.gemini_multi_input_required': '请先输入至少一个Gemini密钥',
'notification.gemini_multi_failed': 'Gemini密钥批量添加失败',
'notification.gemini_multi_summary': 'Gemini批量添加完成成功 {success},跳过 {skipped},失败 {failed}',
'notification.codex_config_added': 'Codex配置添加成功',
'notification.codex_config_updated': 'Codex配置更新成功',
'notification.codex_config_deleted': 'Codex配置删除成功',
'notification.codex_base_url_required': '请填写Codex Base URL',
'notification.claude_config_added': 'Claude配置添加成功',
'notification.claude_config_updated': 'Claude配置更新成功',
'notification.claude_config_deleted': 'Claude配置删除成功',
@@ -483,6 +500,11 @@ const i18n = {
'common.failure': 'Failure',
'common.unknown_error': 'Unknown error',
'common.copy': 'Copy',
'common.custom_headers_label': 'Custom Headers',
'common.custom_headers_hint': 'Optional HTTP headers to send with the request. Leave blank to remove.',
'common.custom_headers_add': 'Add Header',
'common.custom_headers_key_placeholder': 'Header name, e.g. X-Custom-Header',
'common.custom_headers_value_placeholder': 'Header value',
// Page titles
'title.main': 'CLI Proxy API Management Center',
@@ -573,10 +595,14 @@ const i18n = {
'ai_providers.gemini_empty_desc': 'Click the button above to add the first key',
'ai_providers.gemini_item_title': 'Gemini Key',
'ai_providers.gemini_add_modal_title': 'Add Gemini API Key',
'ai_providers.gemini_add_modal_key_label': 'API Key:',
'ai_providers.gemini_add_modal_key_placeholder': 'Please enter Gemini API key',
'ai_providers.gemini_add_modal_key_label': 'API Keys:',
'ai_providers.gemini_add_modal_key_placeholder': 'Enter Gemini API keys (one per line)',
'ai_providers.gemini_add_modal_key_hint': 'You can paste multiple keys, one per line.',
'ai_providers.gemini_add_modal_url_label': 'Base URL (optional):',
'ai_providers.gemini_add_modal_url_placeholder': 'e.g. https://generativelanguage.googleapis.com',
'ai_providers.gemini_edit_modal_title': 'Edit Gemini API Key',
'ai_providers.gemini_edit_modal_key_label': 'API Key:',
'ai_providers.gemini_edit_modal_url_label': 'Base URL (optional):',
'ai_providers.gemini_delete_confirm': 'Are you sure you want to delete this Gemini key?',
'ai_providers.codex_title': 'Codex API Configuration',
@@ -587,13 +613,13 @@ const i18n = {
'ai_providers.codex_add_modal_title': 'Add Codex API Configuration',
'ai_providers.codex_add_modal_key_label': 'API Key:',
'ai_providers.codex_add_modal_key_placeholder': 'Please enter Codex API key',
'ai_providers.codex_add_modal_url_label': 'Base URL (Optional):',
'ai_providers.codex_add_modal_url_label': 'Base URL (Required):',
'ai_providers.codex_add_modal_url_placeholder': 'e.g.: https://api.example.com',
'ai_providers.codex_add_modal_proxy_label': 'Proxy URL (Optional):',
'ai_providers.codex_add_modal_proxy_placeholder': 'e.g.: socks5://proxy.example.com:1080',
'ai_providers.codex_edit_modal_title': 'Edit Codex API Configuration',
'ai_providers.codex_edit_modal_key_label': 'API Key:',
'ai_providers.codex_edit_modal_url_label': 'Base URL (Optional):',
'ai_providers.codex_edit_modal_url_label': 'Base URL (Required):',
'ai_providers.codex_edit_modal_proxy_label': 'Proxy URL (Optional):',
'ai_providers.codex_delete_confirm': 'Are you sure you want to delete this Codex configuration?',
@@ -667,6 +693,8 @@ const i18n = {
'auth_files.filter_all': 'All',
'auth_files.filter_qwen': 'Qwen',
'auth_files.filter_gemini': 'Gemini',
'auth_files.filter_gemini-cli': 'GeminiCLI',
'auth_files.filter_aistudio': 'AIStudio',
'auth_files.filter_claude': 'Claude',
'auth_files.filter_codex': 'Codex',
'auth_files.filter_iflow': 'iFlow',
@@ -674,6 +702,8 @@ const i18n = {
'auth_files.filter_unknown': 'Other',
'auth_files.type_qwen': 'Qwen',
'auth_files.type_gemini': 'Gemini',
'auth_files.type_gemini-cli': 'GeminiCLI',
'auth_files.type_aistudio': 'AIStudio',
'auth_files.type_claude': 'Claude',
'auth_files.type_codex': 'Codex',
'auth_files.type_iflow': 'iFlow',
@@ -837,9 +867,13 @@ const i18n = {
'notification.gemini_key_added': 'Gemini key added successfully',
'notification.gemini_key_updated': 'Gemini key updated successfully',
'notification.gemini_key_deleted': 'Gemini key deleted successfully',
'notification.gemini_multi_input_required': 'Please enter at least one Gemini key',
'notification.gemini_multi_failed': 'Gemini bulk add failed',
'notification.gemini_multi_summary': 'Gemini bulk add finished: {success} added, {skipped} skipped, {failed} failed',
'notification.codex_config_added': 'Codex configuration added successfully',
'notification.codex_config_updated': 'Codex configuration updated successfully',
'notification.codex_config_deleted': 'Codex configuration deleted successfully',
'notification.codex_base_url_required': 'Please enter the Codex Base URL',
'notification.claude_config_added': 'Claude configuration added successfully',
'notification.claude_config_updated': 'Claude configuration updated successfully',
'notification.claude_config_deleted': 'Claude configuration deleted successfully',

View File

@@ -427,6 +427,8 @@
<button class="filter-btn active" data-type="all" data-i18n-text="auth_files.filter_all">All</button>
<button class="filter-btn" data-type="qwen" data-i18n-text="auth_files.filter_qwen">Qwen</button>
<button class="filter-btn" data-type="gemini" data-i18n-text="auth_files.filter_gemini">Gemini</button>
<button class="filter-btn" data-type="gemini-cli" data-i18n-text="auth_files.filter_gemini-cli">GeminiCLI</button>
<button class="filter-btn" data-type="aistudio" data-i18n-text="auth_files.filter_aistudio">AIStudio</button>
<button class="filter-btn" data-type="claude" data-i18n-text="auth_files.filter_claude">Claude</button>
<button class="filter-btn" data-type="codex" data-i18n-text="auth_files.filter_codex">Codex</button>
<button class="filter-btn" data-type="iflow" data-i18n-text="auth_files.filter_iflow">iFlow</button>

View File

@@ -26,6 +26,5 @@
"repository": {
"type": "git",
"url": "local"
},
"dependencies": {}
}
}

View File

@@ -1364,6 +1364,7 @@ textarea::placeholder {
display: flex;
flex-direction: column;
gap: 12px;
min-height: 520px;
}
#config-management .card {
@@ -1383,12 +1384,13 @@ textarea::placeholder {
flex: 1;
display: flex;
flex-direction: column;
min-height: 520px;
}
.yaml-editor {
width: 100%;
flex: 1;
min-height: 360px;
min-height: 520px;
border: 1px solid var(--border-primary);
border-radius: 6px;
padding: 12px 14px;
@@ -1402,6 +1404,7 @@ textarea::placeholder {
#config-management .CodeMirror {
flex: 1;
min-height: 520px;
height: 100%;
font-family: 'SFMono-Regular', 'Consolas', 'Liberation Mono', 'Courier New', monospace;
font-size: 14px;
@@ -1414,8 +1417,10 @@ textarea::placeholder {
#config-management .CodeMirror-scroll {
min-height: 0;
max-height: calc(100vh - 440px);
height: 100%;
max-height: none;
overflow-y: auto;
overscroll-behavior: contain;
}
#config-management .CodeMirror.cm-s-default {
@@ -1458,6 +1463,18 @@ textarea::placeholder {
opacity: 0.6;
}
@media (max-width: 768px) {
.yaml-editor-container,
#config-management .yaml-editor-container {
min-height: 360px;
}
.yaml-editor,
#config-management .CodeMirror {
min-height: 360px;
}
}
.editor-status {
font-size: 13px;
color: var(--text-quaternary);
@@ -1683,6 +1700,27 @@ input:checked+.slider:before {
border: 1px dashed #666666;
}
/* 虚拟认证文件标记样式 */
.virtual-auth-badge {
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-hover) 100%);
color: white;
font-size: 13px;
padding: 4px 8px;
border-radius: 12px;
font-weight: 500;
text-align: center;
display: inline-block;
width: 100%;
box-shadow: 0 2px 4px rgba(59, 130, 246, 0.25);
letter-spacing: 0.3px;
}
[data-theme="dark"] .virtual-auth-badge {
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-hover) 100%);
box-shadow: 0 2px 4px rgba(96, 165, 250, 0.25);
}
.provider-list {
/* 默认不限制高度,动态设置 */
min-height: 0;
@@ -1751,6 +1789,22 @@ input:checked+.slider:before {
justify-content: flex-end;
}
/* 认证文件项的底部布局优化 - 确保状态标签和操作按钮垂直对齐 */
.file-item .item-footer {
align-items: center; /* 垂直居中对齐 */
gap: 12px; /* 增加状态标签和按钮之间的间距 */
}
.file-item .item-stats {
align-items: center; /* 状态徽章垂直居中 */
margin: 0; /* 移除默认外边距 */
}
.file-item .item-actions {
align-items: center; /* 操作按钮垂直居中 */
gap: 6px; /* 按钮之间适当间距 */
}
/* API Keys 和 AI Providers 的按钮组 - 绝对定位到右侧垂直居中 */
.key-item .item-actions,
.provider-item .item-actions {
@@ -2039,9 +2093,13 @@ input:checked+.slider:before {
border-radius: 15px;
width: 90%;
max-width: 550px;
max-height: 90vh;
box-shadow: var(--shadow-modal);
animation: modalSlideIn 0.3s ease;
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
}
@keyframes modalSlideIn {
@@ -2082,6 +2140,9 @@ input:checked+.slider:before {
#modal-body {
padding: 35px 30px 30px 30px;
flex: 1;
min-height: 0;
overflow-y: auto;
}
/* 模态框标题样式 */
@@ -2770,6 +2831,68 @@ input:checked+.slider:before {
align-self: center;
}
.header-input-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.header-input-row .header-input-group {
display: flex;
align-items: center;
gap: 8px;
}
.header-key-input {
flex: 1;
}
.header-value-input {
flex: 2;
}
.header-separator {
color: var(--text-tertiary);
}
.header-badges-wrapper {
display: flex;
flex-direction: column;
gap: 4px;
}
.header-badge-list {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.header-badge {
background: var(--accent-tertiary);
border: 1px solid var(--border-primary);
border-radius: 12px;
padding: 4px 8px;
font-size: 12px;
color: var(--text-secondary);
display: inline-flex;
gap: 4px;
}
.header-badge strong {
font-weight: 600;
color: var(--text-primary);
}
[data-theme="dark"] .header-badge {
background: rgba(59, 130, 246, 0.15);
border-color: rgba(59, 130, 246, 0.3);
color: var(--text-secondary);
}
[data-theme="dark"] .header-badge strong {
color: var(--text-secondary);
}
/* Codex OAuth 样式 */
#codex-oauth-content {
transition: all 0.3s ease;
@@ -3642,6 +3765,7 @@ input:checked+.slider:before {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin-top: 8px;
}
/* 统计徽章基础样式 */