Files
CC-Switch/src-tauri/src/commands/config.rs
T
Jason 36fd61b2a2 refactor: migrate all Tauri commands to camelCase parameters
This commit addresses parameter naming inconsistencies caused by Tauri v2's
requirement for camelCase parameter names in IPC commands.

Backend changes (Rust):
- Updated all command parameters from snake_case to camelCase
- Commands affected:
  * provider.rs: providerId (×4), timeoutSecs
  * import_export.rs: filePath (×2), defaultName
  * config.rs: defaultPath
- Added #[allow(non_snake_case)] attributes for camelCase parameters
- Removed unused QueryUsageParams struct

Frontend changes (TypeScript):
- Removed redundant snake_case parameters from all invoke() calls
- Updated API files:
  * usage.ts: removed debug logs, unified to providerId
  * vscode.ts: updated 8 functions (providerId, timeoutSecs, filePath, defaultName)
  * settings.ts: updated 4 functions (defaultPath, filePath, defaultName)
- Ensured all parameters now use camelCase exclusively

Test updates:
- Updated MSW handlers to accept both old and new parameter formats during transition
- Added i18n mock compatibility for tests

Root cause:
The issue stemmed from Tauri v2 strictly requiring camelCase for command
parameters, while the codebase was using snake_case. This caused parameters
like 'provider_id' to not be recognized by the backend, resulting in
"missing providerId parameter" errors.

BREAKING CHANGE: All Tauri command invocations now require camelCase parameters.
Any external tools or scripts calling these commands must be updated accordingly.

Fixes: Usage query always failing with "missing providerId" error
Fixes: Custom endpoint management not receiving provider ID
Fixes: Import/export dialogs not respecting default paths
2025-11-03 16:50:23 +08:00

128 lines
3.9 KiB
Rust

#![allow(non_snake_case)]
use tauri::AppHandle;
use tauri_plugin_dialog::DialogExt;
use tauri_plugin_opener::OpenerExt;
use crate::app_config::AppType;
use crate::codex_config;
use crate::config::{self, get_claude_settings_path, ConfigStatus};
/// 获取 Claude Code 配置状态
#[tauri::command]
pub async fn get_claude_config_status() -> Result<ConfigStatus, String> {
Ok(config::get_claude_config_status())
}
use std::str::FromStr;
#[tauri::command]
pub async fn get_config_status(app: String) -> Result<ConfigStatus, String> {
match AppType::from_str(&app).map_err(|e| e.to_string())? {
AppType::Claude => Ok(config::get_claude_config_status()),
AppType::Codex => {
let auth_path = codex_config::get_codex_auth_path();
let exists = auth_path.exists();
let path = codex_config::get_codex_config_dir()
.to_string_lossy()
.to_string();
Ok(ConfigStatus { exists, path })
}
}
}
/// 获取 Claude Code 配置文件路径
#[tauri::command]
pub async fn get_claude_code_config_path() -> Result<String, String> {
Ok(get_claude_settings_path().to_string_lossy().to_string())
}
/// 获取当前生效的配置目录
#[tauri::command]
pub async fn get_config_dir(app: String) -> Result<String, String> {
let dir = match AppType::from_str(&app).map_err(|e| e.to_string())? {
AppType::Claude => config::get_claude_config_dir(),
AppType::Codex => codex_config::get_codex_config_dir(),
};
Ok(dir.to_string_lossy().to_string())
}
/// 打开配置文件夹
#[tauri::command]
pub async fn open_config_folder(handle: AppHandle, app: String) -> Result<bool, String> {
let config_dir = match AppType::from_str(&app).map_err(|e| e.to_string())? {
AppType::Claude => config::get_claude_config_dir(),
AppType::Codex => codex_config::get_codex_config_dir(),
};
if !config_dir.exists() {
std::fs::create_dir_all(&config_dir).map_err(|e| format!("创建目录失败: {}", e))?;
}
handle
.opener()
.open_path(config_dir.to_string_lossy().to_string(), None::<String>)
.map_err(|e| format!("打开文件夹失败: {}", e))?;
Ok(true)
}
/// 弹出系统目录选择器并返回用户选择的路径
#[tauri::command]
pub async fn pick_directory(
app: AppHandle,
#[allow(non_snake_case)]
defaultPath: Option<String>,
) -> Result<Option<String>, String> {
let initial = defaultPath
.map(|p| p.trim().to_string())
.filter(|p| !p.is_empty());
let result = tauri::async_runtime::spawn_blocking(move || {
let mut builder = app.dialog().file();
if let Some(path) = initial {
builder = builder.set_directory(path);
}
builder.blocking_pick_folder()
})
.await
.map_err(|e| format!("弹出目录选择器失败: {}", e))?;
match result {
Some(file_path) => {
let resolved = file_path
.simplified()
.into_path()
.map_err(|e| format!("解析选择的目录失败: {}", e))?;
Ok(Some(resolved.to_string_lossy().to_string()))
}
None => Ok(None),
}
}
/// 获取应用配置文件路径
#[tauri::command]
pub async fn get_app_config_path() -> Result<String, String> {
let config_path = config::get_app_config_path();
Ok(config_path.to_string_lossy().to_string())
}
/// 打开应用配置文件夹
#[tauri::command]
pub async fn open_app_config_folder(handle: AppHandle) -> Result<bool, String> {
let config_dir = config::get_app_config_dir();
if !config_dir.exists() {
std::fs::create_dir_all(&config_dir).map_err(|e| format!("创建目录失败: {}", e))?;
}
handle
.opener()
.open_path(config_dir.to_string_lossy().to_string(), None::<String>)
.map_err(|e| format!("打开文件夹失败: {}", e))?;
Ok(true)
}