fix(opencode): fix add/remove provider flow and toast messages

- Create separate removeFromLiveConfig API for additive mode apps
  (remove only removes from live config, not database)
- Fix useSwitchProviderMutation to invalidate opencodeLiveProviderIds
  cache so button state updates correctly after add operation
- Show appropriate toast messages:
  - Add: "已添加到配置" / "Added to config"
  - Remove: "已从配置移除" / "Removed from config"
- Add i18n texts for addToConfigSuccess and removeFromConfigSuccess
This commit is contained in:
Jason
2026-01-17 17:51:32 +08:00
parent 2844f7c557
commit ad6f5b388b
9 changed files with 77 additions and 12 deletions
+10
View File
@@ -60,6 +60,16 @@ pub fn delete_provider(
.map_err(|e| e.to_string())
}
/// Remove provider from live config only (for additive mode apps like OpenCode)
/// Does NOT delete from database - provider remains in the list
#[tauri::command]
pub fn remove_provider_from_live_config(app: String, id: String) -> Result<bool, String> {
let app_type = AppType::from_str(&app).map_err(|e| e.to_string())?;
ProviderService::remove_from_live_config(app_type, &id)
.map(|_| true)
.map_err(|e| e.to_string())
}
/// 切换供应商
fn switch_provider_internal(state: &AppState, app_type: AppType, id: &str) -> Result<(), AppError> {
ProviderService::switch(state, app_type, id)
+1
View File
@@ -713,6 +713,7 @@ pub fn run() {
commands::add_provider,
commands::update_provider,
commands::delete_provider,
commands::remove_provider_from_live_config,
commands::switch_provider,
commands::import_default_config,
commands::get_claude_config_status,
+21
View File
@@ -261,6 +261,27 @@ impl ProviderService {
state.db.delete_provider(app_type.as_str(), id)
}
/// Remove provider from live config only (for additive mode apps like OpenCode)
///
/// Does NOT delete from database - provider remains in the list.
/// This is used when user wants to "remove" a provider from active config
/// but keep it available for future use.
pub fn remove_from_live_config(app_type: AppType, id: &str) -> Result<(), AppError> {
match app_type {
AppType::OpenCode => {
remove_opencode_provider_from_live(id)?;
}
// Future: add other additive mode apps here
_ => {
return Err(AppError::Message(format!(
"App {} does not support remove from live config",
app_type.as_str()
)));
}
}
Ok(())
}
/// Switch to a provider
///
/// Switch flow:
+13 -3
View File
@@ -332,9 +332,19 @@ function App() {
const { provider, action } = confirmAction;
if (action === "remove") {
// Remove from live config only (OpenCode)
// The switch operation with empty/removal semantics
await deleteProvider(provider.id);
// Remove from live config only (for additive mode apps like OpenCode)
// Does NOT delete from database - provider remains in the list
await providersApi.removeFromLiveConfig(provider.id, activeApp);
// Invalidate queries to refresh the isInConfig state
await queryClient.invalidateQueries({
queryKey: ["opencodeLiveProviderIds"],
});
toast.success(
t("notifications.removeFromConfigSuccess", {
defaultValue: "已从配置移除",
}),
{ closeButton: true },
);
} else {
// Delete from database
await deleteProvider(provider.id);
+2
View File
@@ -137,6 +137,8 @@
"providerSaved": "Provider configuration saved",
"providerDeleted": "Provider deleted successfully",
"switchSuccess": "Switch successful!",
"addToConfigSuccess": "Added to config",
"removeFromConfigSuccess": "Removed from config",
"switchFailedTitle": "Switch failed",
"switchFailed": "Switch failed: {{error}}",
"autoImported": "Default provider created from existing configuration",
+2
View File
@@ -137,6 +137,8 @@
"providerSaved": "プロバイダー設定を保存しました",
"providerDeleted": "プロバイダーを削除しました",
"switchSuccess": "切り替え成功!",
"addToConfigSuccess": "設定に追加しました",
"removeFromConfigSuccess": "設定から削除しました",
"switchFailedTitle": "切り替えに失敗しました",
"switchFailed": "切り替えに失敗しました: {{error}}",
"autoImported": "既存設定からデフォルトプロバイダーを自動作成しました",
+2
View File
@@ -137,6 +137,8 @@
"providerSaved": "供应商配置已保存",
"providerDeleted": "供应商删除成功",
"switchSuccess": "切换成功!",
"addToConfigSuccess": "已添加到配置",
"removeFromConfigSuccess": "已从配置移除",
"switchFailedTitle": "切换失败",
"switchFailed": "切换失败:{{error}}",
"autoImported": "已从现有配置创建默认供应商",
+8
View File
@@ -38,6 +38,14 @@ export const providersApi = {
return await invoke("delete_provider", { id, app: appId });
},
/**
* Remove provider from live config only (for additive mode apps like OpenCode)
* Does NOT delete from database - provider remains in the list
*/
async removeFromLiveConfig(id: string, appId: AppId): Promise<boolean> {
return await invoke("remove_provider_from_live_config", { id, app: appId });
},
async switch(id: string, appId: AppId): Promise<boolean> {
return await invoke("switch_provider", { id, app: appId });
},
+18 -9
View File
@@ -155,6 +155,13 @@ export const useSwitchProviderMutation = (appId: AppId) => {
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
// OpenCode: also invalidate live provider IDs cache to update button state
if (appId === "opencode") {
await queryClient.invalidateQueries({
queryKey: ["opencodeLiveProviderIds"],
});
}
// 更新托盘菜单(失败不影响主操作)
try {
await providersApi.updateTrayMenu();
@@ -165,15 +172,17 @@ export const useSwitchProviderMutation = (appId: AppId) => {
);
}
toast.success(
t("notifications.switchSuccess", {
defaultValue: "切换供应商成功",
appName: t(`apps.${appId}`, { defaultValue: appId }),
}),
{
closeButton: true,
},
);
// OpenCode: show "added to config" message instead of "switched"
const messageKey =
appId === "opencode"
? "notifications.addToConfigSuccess"
: "notifications.switchSuccess";
const defaultMessage =
appId === "opencode" ? "已添加到配置" : "切换供应商成功";
toast.success(t(messageKey, { defaultValue: defaultMessage }), {
closeButton: true,
});
},
onError: (error: Error) => {
const detail = extractErrorMessage(error) || t("common.unknown");