Compare commits

..

6 Commits

Author SHA1 Message Date
Supra4E8C
8f71b0d811 style(styles.css): improve layout and spacing for input groups and buttons
- Added margin-bottom to input groups for better spacing.
- Introduced margin-top and alignment for buttons in various input lists to enhance layout consistency.
2025-11-15 14:59:22 +08:00
Supra4E8C
edb723c12b feat(app.js, i18n, index.html, styles.css): enhance auth file management with search and pagination controls
- Implemented search functionality for auth files, allowing users to filter by name, type, or provider.
- Added pagination controls to manage the display of auth files, improving navigation through large datasets.
- Updated internationalization strings to support new search and pagination features in both English and Chinese.
- Enhanced styles for the auth file toolbar, search input, and pagination controls for better user experience.
2025-11-15 14:54:10 +08:00
Supra4E8C
295befe42b feat(app.js): enhance file name handling in CLIProxyManager
- Added logic to generate candidate names based on the raw file name, type, and provider prefixes.
- Implemented checks to return statistics for candidates and their masked versions, improving the accuracy of file management.
- Enhanced the overall handling of file names to support better matching and retrieval of associated stats.
2025-11-14 18:24:22 +08:00
Supra4E8C
a07faddeff feat(app.js, i18n, index.html, styles.css): implement pagination for auth file management
- Added pagination controls to the auth file list in the UI, allowing users to navigate through large sets of files.
- Enhanced the rendering logic to support pagination, including updating the current page and total pages dynamically.
- Updated internationalization strings for pagination in both English and Chinese.
- Introduced new styles for pagination controls to improve user experience and accessibility.
2025-11-14 18:10:37 +08:00
Supra4E8C
5be40092f7 feat(app.js, i18n): add custom model management for Claude API
- Introduced UI elements for adding and managing custom models in the CLIProxyManager, including model name and alias inputs.
- Enhanced the display of model counts and badges in the provider item view.
- Updated internationalization strings to support new model management features in both English and Chinese.
2025-11-13 17:52:13 +08:00
Luis Pater
d422606f99 feat(app.js, styles.css): add main flag for Gemini CLI auth files, update styles and filtering logic 2025-11-13 09:22:14 +08:00
4 changed files with 865 additions and 227 deletions

820
app.js

File diff suppressed because it is too large Load Diff

76
i18n.js
View File

@@ -46,6 +46,8 @@ const i18n = {
'common.custom_headers_add': '添加请求头',
'common.custom_headers_key_placeholder': 'Header 名称,例如 X-Custom-Header',
'common.custom_headers_value_placeholder': 'Header 值',
'common.model_name_placeholder': '模型名称,例如 claude-3-5-sonnet-20241022',
'common.model_alias_placeholder': '模型别名 (可选)',
// 页面标题
'title.main': 'CLI Proxy API Management Center',
@@ -139,14 +141,13 @@ 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_hint': '可一次粘贴多个密钥,每行一个。',
'ai_providers.gemini_add_modal_url_label': 'Base URL (可选):',
'ai_providers.gemini_add_modal_url_placeholder': '例如: https://generativelanguage.googleapis.com',
'ai_providers.gemini_add_modal_key_label': 'API密钥',
'ai_providers.gemini_add_modal_key_placeholder': '输入 Gemini API 密钥',
'ai_providers.gemini_add_modal_key_hint': '逐条输入密钥,可同时指定可选 Base URL。',
'ai_providers.gemini_keys_add_btn': '添加密钥',
'ai_providers.gemini_base_url_placeholder': '可选 Base URL 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 配置',
@@ -184,6 +185,10 @@ const i18n = {
'ai_providers.claude_edit_modal_url_label': 'Base URL (可选):',
'ai_providers.claude_edit_modal_proxy_label': '代理 URL (可选):',
'ai_providers.claude_delete_confirm': '确定要删除这个Claude配置吗',
'ai_providers.claude_models_label': '自定义模型 (可选):',
'ai_providers.claude_models_hint': '为空表示使用全部模型;可填写 name[, alias] 以限制或重命名模型。',
'ai_providers.claude_models_add_btn': '添加模型',
'ai_providers.claude_models_count': '模型数量',
'ai_providers.openai_title': 'OpenAI 兼容提供商',
'ai_providers.openai_add_button': '添加提供商',
@@ -194,10 +199,12 @@ const i18n = {
'ai_providers.openai_add_modal_name_placeholder': '例如: openrouter',
'ai_providers.openai_add_modal_url_label': 'Base URL:',
'ai_providers.openai_add_modal_url_placeholder': '例如: https://openrouter.ai/api/v1',
'ai_providers.openai_add_modal_keys_label': 'API密钥 (每行一个):',
'ai_providers.openai_add_modal_keys_placeholder': 'sk-key1\nsk-key2',
'ai_providers.openai_add_modal_keys_proxy_label': '代理 URL (按行对应,可选):',
'ai_providers.openai_add_modal_keys_proxy_placeholder': 'socks5://proxy.example.com:1080\n',
'ai_providers.openai_add_modal_keys_label': 'API密钥',
'ai_providers.openai_edit_modal_keys_label': 'API密钥',
'ai_providers.openai_keys_hint': '每个密钥可搭配一个可选代理地址,更便于管理。',
'ai_providers.openai_keys_add_btn': '添加密钥',
'ai_providers.openai_key_placeholder': '输入 sk- 开头的密钥',
'ai_providers.openai_proxy_placeholder': '可选代理 URL (如 socks5://...)',
'ai_providers.openai_add_modal_models_label': '模型列表 (name[, alias] 每行一个):',
'ai_providers.openai_models_hint': '示例gpt-4o-mini 或 moonshotai/kimi-k2:free, kimi-k2',
'ai_providers.openai_model_name_placeholder': '模型名称,如 moonshotai/kimi-k2:free',
@@ -206,8 +213,7 @@ const i18n = {
'ai_providers.openai_edit_modal_title': '编辑OpenAI兼容提供商',
'ai_providers.openai_edit_modal_name_label': '提供商名称:',
'ai_providers.openai_edit_modal_url_label': 'Base URL:',
'ai_providers.openai_edit_modal_keys_label': 'API密钥 (每行一个):',
'ai_providers.openai_edit_modal_keys_proxy_label': '代理 URL (按行对应,可选):',
'ai_providers.openai_edit_modal_keys_label': 'API密钥',
'ai_providers.openai_edit_modal_models_label': '模型列表 (name[, alias] 每行一个):',
'ai_providers.openai_delete_confirm': '确定要删除这个OpenAI提供商吗',
'ai_providers.openai_keys_count': '密钥数量',
@@ -222,6 +228,8 @@ const i18n = {
'auth_files.delete_all_button': '删除全部',
'auth_files.empty_title': '暂无认证文件',
'auth_files.empty_desc': '点击上方按钮上传第一个文件',
'auth_files.search_empty_title': '没有匹配的配置文件',
'auth_files.search_empty_desc': '请调整筛选条件或清空搜索关键字再试一次。',
'auth_files.file_size': '大小',
'auth_files.file_modified': '修改时间',
'auth_files.download_button': '下载',
@@ -238,6 +246,13 @@ const i18n = {
'auth_files.delete_filtered_partial': '{type} 认证文件删除完成,成功 {success} 个,失败 {failed} 个',
'auth_files.delete_filtered_none': '当前筛选类型 ({type}) 下没有可删除的认证文件',
'auth_files.files_count': '个文件',
'auth_files.pagination_prev': '上一页',
'auth_files.pagination_next': '下一页',
'auth_files.pagination_info': '第 {current} / {total} 页 · 共 {count} 个文件',
'auth_files.search_label': '搜索配置文件',
'auth_files.search_placeholder': '输入名称、类型或提供方关键字',
'auth_files.page_size_label': '单页数量',
'auth_files.page_size_unit': '个/页',
'auth_files.filter_all': '全部',
'auth_files.filter_qwen': 'Qwen',
'auth_files.filter_gemini': 'Gemini',
@@ -533,6 +548,8 @@ const i18n = {
'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',
'common.model_name_placeholder': 'Model name, e.g. claude-3-5-sonnet-20241022',
'common.model_alias_placeholder': 'Model alias (optional)',
// Page titles
'title.main': 'CLI Proxy API Management Center',
@@ -627,13 +644,12 @@ const i18n = {
'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 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_add_modal_key_placeholder': 'Enter Gemini API key',
'ai_providers.gemini_add_modal_key_hint': 'Add keys one by one and optionally specify a Base URL.',
'ai_providers.gemini_keys_add_btn': 'Add Key',
'ai_providers.gemini_base_url_placeholder': 'Optional Base URL, 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',
@@ -671,6 +687,10 @@ const i18n = {
'ai_providers.claude_edit_modal_url_label': 'Base URL (Optional):',
'ai_providers.claude_edit_modal_proxy_label': 'Proxy URL (Optional):',
'ai_providers.claude_delete_confirm': 'Are you sure you want to delete this Claude configuration?',
'ai_providers.claude_models_label': 'Custom Models (Optional):',
'ai_providers.claude_models_hint': 'Leave empty to allow all models, or add name[, alias] entries to limit/alias them.',
'ai_providers.claude_models_add_btn': 'Add Model',
'ai_providers.claude_models_count': 'Models Count',
'ai_providers.openai_title': 'OpenAI Compatible Providers',
'ai_providers.openai_add_button': 'Add Provider',
@@ -681,10 +701,12 @@ const i18n = {
'ai_providers.openai_add_modal_name_placeholder': 'e.g.: openrouter',
'ai_providers.openai_add_modal_url_label': 'Base URL:',
'ai_providers.openai_add_modal_url_placeholder': 'e.g.: https://openrouter.ai/api/v1',
'ai_providers.openai_add_modal_keys_label': 'API Keys (one per line):',
'ai_providers.openai_add_modal_keys_placeholder': 'sk-key1\nsk-key2',
'ai_providers.openai_add_modal_keys_proxy_label': 'Proxy URL (one per line, optional):',
'ai_providers.openai_add_modal_keys_proxy_placeholder': 'socks5://proxy.example.com:1080\n',
'ai_providers.openai_add_modal_keys_label': 'API Keys',
'ai_providers.openai_edit_modal_keys_label': 'API Keys',
'ai_providers.openai_keys_hint': 'Add each key separately with an optional proxy URL to keep things organized.',
'ai_providers.openai_keys_add_btn': 'Add Key',
'ai_providers.openai_key_placeholder': 'sk-... key',
'ai_providers.openai_proxy_placeholder': 'Optional proxy URL (e.g. socks5://...)',
'ai_providers.openai_add_modal_models_label': 'Model List (name[, alias] one per line):',
'ai_providers.openai_models_hint': 'Example: gpt-4o-mini or moonshotai/kimi-k2:free, kimi-k2',
'ai_providers.openai_model_name_placeholder': 'Model name, e.g. moonshotai/kimi-k2:free',
@@ -693,8 +715,7 @@ const i18n = {
'ai_providers.openai_edit_modal_title': 'Edit OpenAI Compatible Provider',
'ai_providers.openai_edit_modal_name_label': 'Provider Name:',
'ai_providers.openai_edit_modal_url_label': 'Base URL:',
'ai_providers.openai_edit_modal_keys_label': 'API Keys (one per line):',
'ai_providers.openai_edit_modal_keys_proxy_label': 'Proxy URL (one per line, optional):',
'ai_providers.openai_edit_modal_keys_label': 'API Keys',
'ai_providers.openai_edit_modal_models_label': 'Model List (name[, alias] one per line):',
'ai_providers.openai_delete_confirm': 'Are you sure you want to delete this OpenAI provider?',
'ai_providers.openai_keys_count': 'Keys Count',
@@ -709,6 +730,8 @@ const i18n = {
'auth_files.delete_all_button': 'Delete All',
'auth_files.empty_title': 'No Auth Files',
'auth_files.empty_desc': 'Click the button above to upload the first file',
'auth_files.search_empty_title': 'No matching files',
'auth_files.search_empty_desc': 'Try changing the filters or clearing the search box.',
'auth_files.file_size': 'Size',
'auth_files.file_modified': 'Modified',
'auth_files.download_button': 'Download',
@@ -725,6 +748,13 @@ const i18n = {
'auth_files.delete_filtered_partial': '{type} auth files deletion finished: {success} succeeded, {failed} failed',
'auth_files.delete_filtered_none': 'No deletable auth files under the current filter ({type})',
'auth_files.files_count': 'files',
'auth_files.pagination_prev': 'Previous',
'auth_files.pagination_next': 'Next',
'auth_files.pagination_info': 'Page {current} / {total} · {count} files',
'auth_files.search_label': 'Search configs',
'auth_files.search_placeholder': 'Filter by name, type, or provider',
'auth_files.page_size_label': 'Per page',
'auth_files.page_size_unit': 'items',
'auth_files.filter_all': 'All',
'auth_files.filter_qwen': 'Qwen',
'auth_files.filter_gemini': 'Gemini',

View File

@@ -519,7 +519,39 @@
</div>
</div>
<div class="card-content">
<div class="auth-file-toolbar">
<div class="auth-file-search-group">
<label for="auth-files-search-input"
data-i18n="auth_files.search_label">搜索配置文件</label>
<div class="auth-file-search">
<i class="fas fa-search"></i>
<input type="text" id="auth-files-search-input"
data-i18n-placeholder="auth_files.search_placeholder"
placeholder="搜索文件名或类型">
</div>
</div>
<div class="auth-file-page-size">
<label for="auth-files-page-size-input"
data-i18n="auth_files.page_size_label">单页数量</label>
<div class="page-size-input">
<input type="number" id="auth-files-page-size-input" min="3" max="60"
step="1">
<span data-i18n="auth_files.page_size_unit">个/页</span>
</div>
</div>
</div>
<div id="auth-files-list" class="file-list file-grid"></div>
<div id="auth-files-pagination" class="pagination-controls" style="display: none;">
<button class="btn btn-secondary pagination-btn" data-action="prev">
<i class="fas fa-chevron-left"></i>
<span data-i18n="auth_files.pagination_prev">上一页</span>
</button>
<div id="auth-files-pagination-info" class="pagination-info">-</div>
<button class="btn btn-secondary pagination-btn" data-action="next">
<span data-i18n="auth_files.pagination_next">下一页</span>
<i class="fas fa-chevron-right"></i>
</button>
</div>
<input type="file" id="auth-file-input" accept=".json" style="display: none;">
</div>
</div>

View File

@@ -1248,6 +1248,21 @@ body {
transform: translateY(-1px);
}
.btn-small.btn-warning {
background: #ff9800;
color: #fff;
border-color: #ff9800;
cursor: default;
}
.btn-small.btn-warning:disabled,
.btn-small.btn-warning[disabled] {
background: #fb8c00;
border-color: #fb8c00;
color: #fff;
opacity: 1;
}
.btn-small i {
font-size: 13px;
}
@@ -1552,6 +1567,33 @@ input:checked+.slider:before {
gap: 15px;
}
.pagination-controls {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
margin-top: 20px;
flex-wrap: wrap;
}
.pagination-btn {
gap: 6px;
min-width: 120px;
justify-content: center;
display: inline-flex;
align-items: center;
}
.pagination-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.pagination-info {
font-size: 0.95rem;
color: var(--text-secondary);
}
/* 响应式中等屏幕2列 */
@media (max-width: 1400px) {
.file-grid {
@@ -1588,6 +1630,93 @@ input:checked+.slider:before {
white-space: nowrap;
}
/* 认证文件工具栏 */
.auth-file-toolbar {
display: flex;
flex-wrap: wrap;
gap: 18px;
align-items: flex-end;
margin-bottom: 18px;
}
.auth-file-search-group {
flex: 1;
min-width: 240px;
display: flex;
flex-direction: column;
gap: 6px;
}
.auth-file-search-group label,
.auth-file-page-size label {
font-weight: 600;
color: var(--text-secondary);
}
.auth-file-search {
display: flex;
align-items: center;
border: 1px solid var(--border-primary);
border-radius: 10px;
padding: 0 12px;
background: var(--bg-secondary);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.03);
}
[data-theme="dark"] .auth-file-search {
background: var(--bg-tertiary);
box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.04);
}
.auth-file-search i {
color: var(--text-tertiary);
margin-right: 8px;
}
.auth-file-search input {
border: none;
background: transparent;
color: var(--text-primary);
width: 100%;
padding: 10px 0;
font-size: 0.95rem;
}
.auth-file-search input:focus {
outline: none;
}
.auth-file-page-size {
min-width: 180px;
display: flex;
flex-direction: column;
gap: 6px;
}
.page-size-input {
display: flex;
align-items: center;
gap: 8px;
border: 1px solid var(--border-primary);
border-radius: 10px;
padding: 8px 12px;
background: var(--bg-quaternary);
}
.page-size-input input {
width: 80px;
padding: 6px 8px;
border: 1px solid var(--border-secondary);
border-radius: 6px;
background: var(--bg-primary);
color: var(--text-primary);
}
.page-size-input span {
font-size: 0.9rem;
color: var(--text-tertiary);
}
/* 认证文件筛选按钮 */
.auth-file-filter {
display: flex;
@@ -2811,6 +2940,7 @@ input:checked+.slider:before {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 10px;
}
.model-input-row .input-group {
@@ -2831,10 +2961,44 @@ input:checked+.slider:before {
align-self: center;
}
.api-key-input-list {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 10px;
}
.api-key-input-group {
display: flex;
gap: 8px;
width: 100%;
}
.api-key-input-group .api-key-value-input {
flex: 2;
}
.api-key-input-group .api-key-proxy-input {
flex: 1;
min-width: 180px;
}
.api-key-input-group .api-key-remove-btn {
align-self: center;
}
.api-key-input-list + .btn,
.model-input-list + .btn,
.header-input-list + .btn {
margin-top: 4px;
align-self: flex-start;
}
.header-input-list {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 10px;
}
.header-input-row .header-input-group {