mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-27 08:14:33 +08:00
refactor(provider): replace startup auto-import with manual import button
Remove the startup loop in lib.rs that auto-imported default providers for Claude/Codex/Gemini. Move config snippet extraction logic into the import_default_config command so it works when triggered manually. Add an "Import Current Config" button to ProviderEmptyState, wired via useMutation in ProviderList (shown only for standard apps). Update i18n keys (zh/en/ja) with new button labels and revised empty state text.
This commit is contained in:
@@ -93,7 +93,29 @@ pub fn switch_provider(
|
||||
}
|
||||
|
||||
fn import_default_config_internal(state: &AppState, app_type: AppType) -> Result<bool, AppError> {
|
||||
ProviderService::import_default_config(state, app_type)
|
||||
let imported = ProviderService::import_default_config(state, app_type.clone())?;
|
||||
|
||||
if imported {
|
||||
// Extract common config snippet (mirrors old startup logic in lib.rs)
|
||||
if state
|
||||
.db
|
||||
.get_config_snippet(app_type.as_str())
|
||||
.ok()
|
||||
.flatten()
|
||||
.is_none()
|
||||
{
|
||||
match ProviderService::extract_common_config_snippet(state, app_type.clone()) {
|
||||
Ok(snippet) if !snippet.is_empty() && snippet != "{}" => {
|
||||
let _ = state
|
||||
.db
|
||||
.set_config_snippet(app_type.as_str(), Some(snippet));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(imported)
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "test-hooks"), doc(hidden))]
|
||||
|
||||
+1
-46
@@ -448,52 +448,7 @@ pub fn run() {
|
||||
Err(e) => log::warn!("✗ Failed to read skills migration flag: {e}"),
|
||||
}
|
||||
|
||||
// 2. 导入供应商配置(已有内置检查:该应用已有供应商则跳过)
|
||||
for app in [
|
||||
crate::app_config::AppType::Claude,
|
||||
crate::app_config::AppType::Codex,
|
||||
crate::app_config::AppType::Gemini,
|
||||
] {
|
||||
match crate::services::provider::ProviderService::import_default_config(
|
||||
&app_state,
|
||||
app.clone(),
|
||||
) {
|
||||
Ok(true) => {
|
||||
log::info!("✓ Imported default provider for {}", app.as_str());
|
||||
|
||||
// 首次运行:自动提取通用配置片段(仅当通用配置为空时)
|
||||
if app_state
|
||||
.db
|
||||
.get_config_snippet(app.as_str())
|
||||
.ok()
|
||||
.flatten()
|
||||
.is_none()
|
||||
{
|
||||
match crate::services::provider::ProviderService::extract_common_config_snippet(&app_state, app.clone()) {
|
||||
Ok(snippet) if !snippet.is_empty() && snippet != "{}" => {
|
||||
if let Err(e) = app_state.db.set_config_snippet(app.as_str(), Some(snippet)) {
|
||||
log::warn!("✗ Failed to save common config snippet for {}: {e}", app.as_str());
|
||||
} else {
|
||||
log::info!("✓ Extracted common config snippet for {}", app.as_str());
|
||||
}
|
||||
}
|
||||
Ok(_) => log::debug!("○ No common config to extract for {}", app.as_str()),
|
||||
Err(e) => log::debug!("○ Failed to extract common config for {}: {e}", app.as_str()),
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(false) => {} // 已有供应商,静默跳过
|
||||
Err(e) => {
|
||||
log::debug!(
|
||||
"○ No default provider to import for {}: {}",
|
||||
app.as_str(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2.1 OpenCode 供应商导入(累加式模式,需特殊处理)
|
||||
// 2. OpenCode 供应商导入(累加式模式,需特殊处理)
|
||||
// OpenCode 与其他应用不同:配置文件中可同时存在多个供应商
|
||||
// 需要遍历 provider 字段下的每个供应商并导入
|
||||
match crate::services::provider::import_opencode_providers_from_live(&app_state) {
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { Users } from "lucide-react";
|
||||
import { Download, Users } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
interface ProviderEmptyStateProps {
|
||||
onCreate?: () => void;
|
||||
onImport?: () => void;
|
||||
}
|
||||
|
||||
export function ProviderEmptyState({ onCreate }: ProviderEmptyStateProps) {
|
||||
export function ProviderEmptyState({
|
||||
onCreate,
|
||||
onImport,
|
||||
}: ProviderEmptyStateProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@@ -18,11 +22,19 @@ export function ProviderEmptyState({ onCreate }: ProviderEmptyStateProps) {
|
||||
<p className="mt-2 max-w-sm text-sm text-muted-foreground">
|
||||
{t("provider.noProvidersDescription")}
|
||||
</p>
|
||||
{onCreate && (
|
||||
<Button className="mt-6" onClick={onCreate}>
|
||||
{t("provider.addProvider")}
|
||||
</Button>
|
||||
)}
|
||||
<div className="mt-6 flex flex-col gap-2">
|
||||
{onImport && (
|
||||
<Button onClick={onImport}>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
{t("provider.importCurrent")}
|
||||
</Button>
|
||||
)}
|
||||
{onCreate && (
|
||||
<Button variant={onImport ? "outline" : "default"} onClick={onCreate}>
|
||||
{t("provider.addProvider")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ import {
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { Search, X } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { toast } from "sonner";
|
||||
import type { Provider } from "@/types";
|
||||
import type { AppId } from "@/lib/api";
|
||||
import { providersApi } from "@/lib/api/providers";
|
||||
@@ -179,6 +180,23 @@ export function ProviderList({
|
||||
const [isSearchOpen, setIsSearchOpen] = useState(false);
|
||||
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
// Import current live config as default provider
|
||||
const queryClient = useQueryClient();
|
||||
const importMutation = useMutation({
|
||||
mutationFn: () => providersApi.importDefault(appId),
|
||||
onSuccess: (imported) => {
|
||||
if (imported) {
|
||||
queryClient.invalidateQueries({ queryKey: ["providers", appId] });
|
||||
toast.success(t("provider.importCurrentDescription"));
|
||||
} else {
|
||||
toast.info(t("provider.noProviders"));
|
||||
}
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
const key = event.key.toLowerCase();
|
||||
@@ -231,8 +249,17 @@ export function ProviderList({
|
||||
);
|
||||
}
|
||||
|
||||
// Only show import button for standard apps (not additive-mode apps like OpenCode/OpenClaw)
|
||||
const showImportButton =
|
||||
appId === "claude" || appId === "codex" || appId === "gemini";
|
||||
|
||||
if (sortedProviders.length === 0) {
|
||||
return <ProviderEmptyState onCreate={onCreate} />;
|
||||
return (
|
||||
<ProviderEmptyState
|
||||
onCreate={onCreate}
|
||||
onImport={showImportButton ? () => importMutation.mutate() : undefined}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const renderProviderList = () => (
|
||||
|
||||
@@ -77,7 +77,9 @@
|
||||
"tabProvider": "Provider",
|
||||
"tabUniversal": "Universal",
|
||||
"noProviders": "No providers added yet",
|
||||
"noProvidersDescription": "Click the \"Add Provider\" button in the top right to configure your first API provider",
|
||||
"noProvidersDescription": "Import your current live config below, or manually add a new provider",
|
||||
"importCurrent": "Import Current Config",
|
||||
"importCurrentDescription": "Import current live config as default provider",
|
||||
"currentlyUsing": "Currently Using",
|
||||
"enable": "Enable",
|
||||
"inUse": "In Use",
|
||||
|
||||
@@ -77,7 +77,9 @@
|
||||
"tabProvider": "プロバイダー",
|
||||
"tabUniversal": "統一プロバイダー",
|
||||
"noProviders": "まだプロバイダーがありません",
|
||||
"noProvidersDescription": "右上の「プロバイダーを追加」を押して最初の API プロバイダーを登録してください",
|
||||
"noProvidersDescription": "下の「現在の設定をインポート」ボタンで既存の設定を取り込むか、新しいプロバイダーを手動で追加してください",
|
||||
"importCurrent": "現在の設定をインポート",
|
||||
"importCurrentDescription": "現在使用中の設定をデフォルトプロバイダーとしてインポート",
|
||||
"currentlyUsing": "現在使用中",
|
||||
"enable": "有効化",
|
||||
"inUse": "使用中",
|
||||
|
||||
@@ -77,7 +77,9 @@
|
||||
"tabProvider": "供应商",
|
||||
"tabUniversal": "统一供应商",
|
||||
"noProviders": "还没有添加任何供应商",
|
||||
"noProvidersDescription": "点击右上角的\"添加供应商\"按钮开始配置您的第一个API供应商",
|
||||
"noProvidersDescription": "点击下方的\"导入当前配置\"按钮导入已有配置,或手动添加新的供应商",
|
||||
"importCurrent": "导入当前配置",
|
||||
"importCurrentDescription": "将当前正在使用的配置导入为默认供应商",
|
||||
"currentlyUsing": "当前使用",
|
||||
"enable": "启用",
|
||||
"inUse": "使用中",
|
||||
|
||||
Reference in New Issue
Block a user