feat(settings): add 'Apply to Claude Code extension' toggle

- Apply immediately on save (write or remove primaryApiKey)
- Honor setting on provider switch (enabled: write for non-official, remove for official; disabled: no auto writes)
- Remove per-provider Claude plugin buttons from ProviderList
- Upsert primaryApiKey=any preserving other fields; respect override dir
- Add zh/en i18n for the new setting
This commit is contained in:
Jason
2025-10-10 16:35:21 +08:00
parent 70d8d2cc43
commit c350e64687
8 changed files with 87 additions and 87 deletions

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React from "react";
import { useTranslation } from "react-i18next";
import { Provider } from "../types";
import { Play, Edit3, Trash2, CheckCircle2, Users, Check } from "lucide-react";
@@ -58,55 +58,7 @@ const ProviderList: React.FC<ProviderListProps> = ({
}
};
const [claudeApplied, setClaudeApplied] = useState<boolean>(false);
// 检查 Claude 插件配置是否已应用
useEffect(() => {
const checkClaude = async () => {
if (appType !== "claude" || !currentProviderId) {
setClaudeApplied(false);
return;
}
try {
const applied = await window.api.isClaudePluginApplied();
setClaudeApplied(applied);
} catch (error) {
console.error(t("console.setupListenerFailed"), error);
setClaudeApplied(false);
}
};
checkClaude();
}, [appType, currentProviderId, providers, t]);
const handleApplyToClaudePlugin = async () => {
try {
await window.api.applyClaudePluginConfig({ official: false });
onNotify?.(t("notifications.appliedToClaudePlugin"), "success", 3000);
setClaudeApplied(true);
} catch (error: any) {
console.error(error);
const msg =
error && error.message
? error.message
: t("notifications.syncClaudePluginFailed");
onNotify?.(msg, "error", 5000);
}
};
const handleRemoveFromClaudePlugin = async () => {
try {
await window.api.applyClaudePluginConfig({ official: true });
onNotify?.(t("notifications.removedFromClaudePlugin"), "success", 3000);
setClaudeApplied(false);
} catch (error: any) {
console.error(error);
const msg =
error && error.message
? error.message
: t("notifications.syncClaudePluginFailed");
onNotify?.(msg, "error", 5000);
}
};
// 列表页不再提供 Claude 插件按钮,统一在“设置”中控制
// 对供应商列表进行排序
const sortedProviders = Object.values(providers).sort((a, b) => {
@@ -201,34 +153,6 @@ const ProviderList: React.FC<ProviderListProps> = ({
</div>
<div className="flex items-center gap-2 ml-4">
{appType === "claude" ? (
<div className="flex-shrink-0">
{provider.category !== "official" && isCurrent && (
<button
onClick={() =>
claudeApplied
? handleRemoveFromClaudePlugin()
: handleApplyToClaudePlugin()
}
className={cn(
"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md transition-colors w-full whitespace-nowrap justify-center",
claudeApplied
? "border border-gray-300 text-gray-600 hover:border-red-300 hover:text-red-600 hover:bg-red-50 dark:border-gray-600 dark:text-gray-400 dark:hover:border-red-800 dark:hover:text-red-400 dark:hover:bg-red-900/20"
: "border border-gray-300 text-gray-700 hover:border-green-300 hover:text-green-600 hover:bg-green-50 dark:border-gray-600 dark:text-gray-300 dark:hover:border-green-700 dark:hover:text-green-400 dark:hover:bg-green-900/20",
)}
title={
claudeApplied
? t("provider.removeFromClaudePlugin")
: t("provider.applyToClaudePlugin")
}
>
{claudeApplied
? t("provider.removeFromClaudePlugin")
: t("provider.applyToClaudePlugin")}
</button>
)}
</div>
) : null}
<button
onClick={() => onSwitch(provider.id)}
disabled={isCurrent}