From 1a89267986e8247ad9002ccd971e8abea93f1c9e Mon Sep 17 00:00:00 2001 From: YoVinchen Date: Sat, 22 Nov 2025 03:26:28 +0800 Subject: [PATCH] feat(deeplink): add Claude model fields support and enhance import dialog - Add Claude-specific model field support in deeplink import: * Support model (ANTHROPIC_MODEL) - general default model * Support haikuModel (ANTHROPIC_DEFAULT_HAIKU_MODEL) * Support sonnetModel (ANTHROPIC_DEFAULT_SONNET_MODEL) * Support opusModel (ANTHROPIC_DEFAULT_OPUS_MODEL) * Backend: Update DeepLinkImportRequest struct to include optional model fields * Frontend: Add TypeScript type definitions for new model parameters - Enhance deeplink demo page (deplink.html): * Add 5 new Claude configuration examples showcasing different model setups * Add parameter documentation with required/optional tags * Include basic config (no models), single model, complete 4-model, partial models, and third-party provider examples * Improve visual design with param-list component and color-coded badges * Add detailed descriptions for each configuration scenario - Redesign DeepLinkImportDialog layout: * Switch from 3-column to compact 2-column grid layout * Reduce dialog width from 500px to 650px for better content display * Add dedicated section for Claude model configurations with blue highlight box * Use uppercase labels and smaller text for more information density * Add truncation and tooltips for long URLs * Improve visual hierarchy with spacing and grouping * Increase z-index to 9999 to ensure dialog appears on top - Minor UI refinements: * Update App.tsx layout adjustments * Optimize McpFormModal styling * Refine ProviderCard and BasicFormFields components This enables users to import Claude providers with precise model configurations via deeplink. --- deplink.html | 278 +++++++++++++++++- src-tauri/src/deeplink.rs | 30 +- src/App.tsx | 9 +- src/components/DeepLinkImportDialog.tsx | 136 ++++++--- src/components/mcp/McpFormModal.tsx | 14 +- src/components/providers/ProviderCard.tsx | 2 +- .../providers/forms/BasicFormFields.tsx | 5 +- src/lib/api/deeplink.ts | 4 + 8 files changed, 402 insertions(+), 76 deletions(-) diff --git a/deplink.html b/deplink.html index 5fe2c5d..a8975cb 100644 --- a/deplink.html +++ b/deplink.html @@ -263,6 +263,34 @@ color: #e91e63; } + .param-list { + background: #f8f9fa; + border-left: 3px solid #3498db; + padding: 12px; + border-radius: 6px; + margin: 12px 0; + font-size: 13px; + line-height: 1.8; + color: #495057; + font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace; + } + + .param-tag { + display: inline-block; + padding: 2px 8px; + border-radius: 4px; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + margin-right: 6px; + background: #3498db; + color: white; + } + + .param-tag.optional { + background: #95a5a6; + } + @media (max-width: 768px) { .header h1 { font-size: 24px; @@ -293,28 +321,90 @@ + - 📥 导入 Claude Official + 📥 导入基础配置 + - 📥 导入测试环境 + 📥 导入带默认模型 + + + + + + + + @@ -326,11 +416,33 @@ + + + +

Gemini 供应商

+ + + +
@@ -404,7 +582,7 @@
- @@ -432,8 +610,47 @@
- + + + 通用模型字段,适用于所有应用类型 + +
+ + +
+
+

+ 📋 Claude 专用模型字段(可选) +

+

+ 可以根据需要设置特定的模型字段,这些字段仅在 Claude 应用中生效 +

+ +
+ + + + 对应环境变量:ANTHROPIC_DEFAULT_HAIKU_MODEL + +
+ +
+ + + + 对应环境变量:ANTHROPIC_DEFAULT_SONNET_MODEL + +
+ +
+ + + + 对应环境变量:ANTHROPIC_DEFAULT_OPUS_MODEL + +
+
@@ -458,6 +675,18 @@
diff --git a/src-tauri/src/deeplink.rs b/src-tauri/src/deeplink.rs index 8b7cf05..f99a31b 100644 --- a/src-tauri/src/deeplink.rs +++ b/src-tauri/src/deeplink.rs @@ -37,6 +37,15 @@ pub struct DeepLinkImportRequest { /// Optional notes/description #[serde(skip_serializing_if = "Option::is_none")] pub notes: Option, + /// Optional Haiku model (Claude only, v3.7.1+) + #[serde(skip_serializing_if = "Option::is_none")] + pub haiku_model: Option, + /// Optional Sonnet model (Claude only, v3.7.1+) + #[serde(skip_serializing_if = "Option::is_none")] + pub sonnet_model: Option, + /// Optional Opus model (Claude only, v3.7.1+) + #[serde(skip_serializing_if = "Option::is_none")] + pub opus_model: Option, } /// Parse a ccswitch:// URL into a DeepLinkImportRequest @@ -133,6 +142,11 @@ pub fn parse_deeplink_url(url_str: &str) -> Result Result { diff --git a/src/App.tsx b/src/App.tsx index fc385a3..cdf172e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -509,8 +509,9 @@ function App() {
{renderContent()} @@ -553,8 +554,8 @@ function App() { message={ confirmDelete ? t("confirm.deleteProviderMessage", { - name: confirmDelete.name, - }) + name: confirmDelete.name, + }) : "" } onConfirm={() => void handleConfirmDelete()} diff --git a/src/components/DeepLinkImportDialog.tsx b/src/components/DeepLinkImportDialog.tsx index 49f9f65..9e2fed0 100644 --- a/src/components/DeepLinkImportDialog.tsx +++ b/src/components/DeepLinkImportDialog.tsx @@ -96,8 +96,8 @@ export function DeepLinkImportDialog() { : "****"; return ( - - + + {/* 标题显式左对齐,避免默认居中样式影响 */} {t("deeplink.confirmImport")} @@ -106,82 +106,120 @@ export function DeepLinkImportDialog() { - {/* 主体内容整体右移,略大于标题内边距,让内容看起来不贴边 */} -
- {/* App Type */} -
-
- {t("deeplink.app")} + {/* 使用两列布局压缩内容 */} +
+ {/* 第一行:应用类型 + 供应商名称 */} +
+
+
+ {t("deeplink.app")} +
+
+ {request.app} +
-
- {request.app} +
+
+ {t("deeplink.providerName")} +
+
+ {request.name} +
- {/* Provider Name */} -
-
- {t("deeplink.providerName")} + {/* 第二行:官网 + 端点 */} +
+
+
+ {t("deeplink.homepage")} +
+
+ {request.homepage} +
-
{request.name}
-
- - {/* Homepage */} -
-
- {t("deeplink.homepage")} -
-
- {request.homepage} +
+
+ {t("deeplink.endpoint")} +
+
+ {request.endpoint} +
- {/* API Endpoint */} -
-
- {t("deeplink.endpoint")} -
-
- {request.endpoint} -
-
- - {/* API Key (masked) */} -
-
+ {/* 第三行:API Key */} +
+
{t("deeplink.apiKey")}
-
+
{maskedApiKey}
- {/* Model (if present) */} + {/* 第四行:默认模型(如果有) */} {request.model && ( -
-
+
+
{t("deeplink.model")}
-
- {request.model} +
{request.model}
+
+ )} + + {/* Claude 专用模型字段(紧凑布局) */} + {request.app === "claude" && (request.haikuModel || request.sonnetModel || request.opusModel) && ( +
+
+ {t("deeplink.claudeModels", "Claude 模型配置")} +
+ +
+ {request.haikuModel && ( +
+ Haiku: +
+ {request.haikuModel} +
+
+ )} + + {request.sonnetModel && ( +
+ Sonnet: +
+ {request.sonnetModel} +
+
+ )} + + {request.opusModel && ( +
+ Opus: +
+ {request.opusModel} +
+
+ )}
)} - {/* Notes (if present) */} + {/* 备注(如果有) */} {request.notes && ( -
-
+
+
{t("deeplink.notes")}
-
+
{request.notes}
)} - {/* Warning */} -
+ {/* 警告提示(紧凑版) */} +
{t("deeplink.warning")}
diff --git a/src/components/mcp/McpFormModal.tsx b/src/components/mcp/McpFormModal.tsx index b7af81d..4006fcd 100644 --- a/src/components/mcp/McpFormModal.tsx +++ b/src/components/mcp/McpFormModal.tsx @@ -440,10 +440,11 @@ const McpFormModal: React.FC = ({ @@ -454,10 +455,11 @@ const McpFormModal: React.FC = ({ key={preset.id} type="button" onClick={() => applyPreset(idx)} - className={`inline-flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-colors ${selectedPreset === idx + className={`inline-flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-colors ${ + selectedPreset === idx ? "bg-emerald-500 text-white dark:bg-emerald-600" : "bg-accent text-muted-foreground hover:bg-accent/80" - }`} + }`} title={t(descriptionKey)} > {preset.id} @@ -631,9 +633,7 @@ const McpFormModal: React.FC = ({
{(isEditing || selectedPreset === -1) && (